GCC Code Coverage Report


Directory: ./
File: sql-common/client.cc
Date: 2022-12-06 21:40:42
Exec Total Coverage
Lines: 3274 4137 79.1%
Branches: 2642 5854 45.1%

Line Branch Exec Source
1 /* Copyright (c) 2003, 2022, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 Without limiting anything contained in the foregoing, this file,
15 which is part of C Driver for MySQL (Connector/C), is also subject to the
16 Universal FOSS Exception, version 1.0, a copy of which can be found at
17 http://oss.oracle.com/licenses/universal-foss-exception.
18
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License, version 2.0, for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
27
28 /*
29 This file is included by both libmysql.c (the MySQL client C API)
30 and the mysqld server to connect to another MYSQL server.
31
32 The differences for the two cases are:
33
34 - Things that only works for the client:
35 - Trying to automatically determine user name if not supplied to
36 mysql_real_connect()
37 - Support for reading local file with LOAD DATA LOCAL
38 - SHARED memory handling
39 - Prepared statements
40 - Things that only works for the server
41
42 In all other cases, code should be identical for the client and
43 server.
44 */
45
46 #include <stdarg.h>
47 #include <sys/types.h>
48
49 #include "m_ctype.h"
50 #include "m_string.h"
51 #include "my_config.h"
52 #include "my_sys.h"
53 #include "mysys_err.h"
54 #ifndef _WIN32
55 #include <netdb.h>
56 #endif
57 #ifdef HAVE_NETINET_IN_H
58 #include <netinet/in.h>
59 #endif
60 #include <stdio.h>
61
62 #include <algorithm>
63 #include <string>
64
65 #include "base64.h"
66 #include "client_async_authentication.h"
67 #include "compression.h" // validate_compression_attributes
68 #include "errmsg.h"
69 #include "lex_string.h"
70 #include "map_helpers.h"
71 #include "my_byteorder.h"
72 #include "my_compiler.h"
73 #include "my_dbug.h"
74 #include "my_default.h"
75 #include "my_inttypes.h"
76 #include "my_io.h"
77 #include "my_loglevel.h"
78 #include "my_macros.h"
79 #include "my_openssl_fips.h" // OPENSSL_ERROR_LENGTH, set_fips_mode
80 #include "my_psi_config.h"
81 #include "my_shm_defaults.h"
82 #include "mysql.h"
83 #include "mysql/client_authentication.h"
84 #include "mysql/plugin_auth_common.h"
85 #include "mysql/psi/mysql_memory.h"
86 #include "mysql/service_mysql_alloc.h"
87 #include "mysql_version.h"
88 #include "mysqld_error.h"
89 #include "template_utils.h"
90 #include "typelib.h"
91 #include "violite.h"
92
93 #if !defined(_WIN32)
94 #include "my_thread.h" /* because of signal()*/
95 #endif /* !defined(_WIN32) */
96
97 #include <signal.h>
98 #include <sys/stat.h>
99 #include <time.h>
100
101 #ifdef HAVE_PWD_H
102 #include <pwd.h>
103 #endif
104
105 #ifdef HAVE_SYS_SELECT_H
106 #include <sys/select.h>
107 #endif
108
109 #ifdef HAVE_SYS_UN_H
110 #include <sys/un.h>
111 #endif
112
113 #ifndef _WIN32
114 #include <errno.h>
115
116 #define INVALID_SOCKET -1
117 #endif
118
119 #include <mysql/client_plugin.h>
120 #include <openssl/x509v3.h>
121
122 #include <new>
123
124 #include "../libmysql/init_commands_array.h"
125 #include "../libmysql/mysql_trace.h" /* MYSQL_TRACE() instrumentation */
126 #include "sql_common.h"
127 #ifdef MYSQL_SERVER
128 #include "mysql_com_server.h"
129 #include "sql/client_settings.h"
130 #else
131 #include "libmysql/client_settings.h"
132 #endif
133 #include "client_extensions_macros.h"
134 #include "sql/log_event.h" /* Log_event_type */
135 #include "sql/rpl_constants.h" /* mysql_binlog_XXX() */
136
137 using std::string;
138 using std::swap;
139
140 #define STATE_DATA(M) \
141 (NULL != (M) ? &(MYSQL_EXTENSION_PTR(M)->state_change) : NULL)
142
143 #define ADD_INFO(M, element, type) \
144 { \
145 M = STATE_DATA(mysql); \
146 M->info_list[type].head_node = \
147 list_add(M->info_list[type].head_node, element); \
148 }
149
150 #define native_password_plugin_name "mysql_native_password"
151 #define caching_sha2_password_plugin_name "caching_sha2_password"
152
153 PSI_memory_key key_memory_mysql_options;
154 PSI_memory_key key_memory_MYSQL_DATA;
155 PSI_memory_key key_memory_MYSQL;
156 PSI_memory_key key_memory_MYSQL_RES;
157 PSI_memory_key key_memory_MYSQL_ROW;
158 PSI_memory_key key_memory_MYSQL_state_change_info;
159 PSI_memory_key key_memory_MYSQL_HANDSHAKE;
160 PSI_memory_key key_memory_MYSQL_ssl_session_data;
161
162 #if defined(_WIN32)
163 PSI_memory_key key_memory_create_shared_memory;
164 #endif /* _WIN32 */
165
166 #ifdef HAVE_PSI_INTERFACE
167 /*
168 This code is common to the client and server,
169 and also used in the server when server A connects to server B,
170 for example with replication.
171 Therefore, the code is also instrumented.
172 */
173
174 static PSI_memory_info all_client_memory[] = {
175 #if defined(_WIN32)
176 {&key_memory_create_shared_memory, "create_shared_memory", 0, 0,
177 PSI_DOCUMENT_ME},
178 #endif /* _WIN32 */
179
180 {&key_memory_mysql_options, "mysql_options", 0, 0, PSI_DOCUMENT_ME},
181 {&key_memory_MYSQL_DATA, "MYSQL_DATA", 0, 0, PSI_DOCUMENT_ME},
182 {&key_memory_MYSQL, "MYSQL", 0, 0, PSI_DOCUMENT_ME},
183 {&key_memory_MYSQL_RES, "MYSQL_RES", 0, 0, PSI_DOCUMENT_ME},
184 {&key_memory_MYSQL_ROW, "MYSQL_ROW", 0, 0, PSI_DOCUMENT_ME},
185 {&key_memory_MYSQL_state_change_info, "MYSQL_STATE_CHANGE_INFO", 0, 0,
186 PSI_DOCUMENT_ME},
187 {&key_memory_MYSQL_HANDSHAKE, "MYSQL_HANDSHAKE", 0, 0, PSI_DOCUMENT_ME},
188 {&key_memory_MYSQL_ssl_session_data, "MYSQL_SSL_session", 0, 0,
189 "Saved SSL sessions"}};
190
191 /* SSL_SESSION_is_resumable is openssl 1.1.1+ */
192 #if OPENSSL_VERSION_NUMBER < 0x10101000L
193 #define SSL_SESSION_is_resumable(x) true
194 #endif
195
196 12109 void init_client_psi_keys(void) {
197 12109 const char *category = "client";
198 int count;
199
200 12109 count = static_cast<int>(array_elements(all_client_memory));
201 12109 mysql_memory_register(category, all_client_memory, count);
202 12109 }
203
204 #endif /* HAVE_PSI_INTERFACE */
205
206 uint mysql_port = 0;
207 char *mysql_unix_port = nullptr;
208 const char *unknown_sqlstate = "HY000";
209 const char *not_error_sqlstate = "00000";
210 const char *cant_connect_sqlstate = "08001";
211 #if defined(_WIN32)
212 const char *def_shared_memory_base_name = default_shared_memory_base_name;
213 #endif
214 ulong g_net_buffer_length = 8192;
215 ulong g_max_allowed_packet = 1024L * 1024L * 1024L;
216
217 static void mysql_prune_stmt_list(MYSQL *mysql);
218 static int read_com_query_metadata(MYSQL *mysql, uchar *pos, ulong field_count);
219
220 CHARSET_INFO *default_client_charset_info = &my_charset_latin1;
221
222 /* Server error code and message */
223 unsigned int mysql_server_last_errno;
224 char mysql_server_last_error[MYSQL_ERRMSG_SIZE];
225 /* forward declaration */
226 static int read_one_row(MYSQL *mysql, uint fields, MYSQL_ROW row,
227 ulong *lengths);
228 static net_async_status read_one_row_nonblocking(MYSQL *mysql, uint fields,
229 MYSQL_ROW row, ulong *lengths,
230 int *res);
231 /**
232 Free async_qp_data buffer in async_context.
233
234 @param async_context pointer to asynchronous context structure
235 */
236 112 void inline free_async_qp_data(MYSQL_ASYNC *async_context) {
237
1/2
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
112 if (async_context->async_qp_data) {
238 112 my_free(async_context->async_qp_data);
239 112 async_context->async_qp_data = nullptr;
240 112 async_context->async_qp_data_length = 0;
241 }
242 112 }
243
244 /**
245 Set async_context to idle status, free async_qp_data buffer.
246
247 @param async_context pointer to asynchronous context structure
248 */
249 void inline set_query_idle(MYSQL_ASYNC *async_context) {
250 async_context->async_op_status = ASYNC_OP_UNSET;
251 async_context->async_query_state = QUERY_IDLE;
252 async_context->async_query_length = 0;
253 DBUG_PRINT("async", ("set state=%d", async_context->async_query_state));
254 free_async_qp_data(async_context);
255 }
256
257 /**
258 Convert the connect timeout option to a timeout value for VIO
259 functions (vio_socket_connect() and vio_io_wait()).
260
261 @param mysql Connection handle (client side).
262
263 @return The timeout value in milliseconds, or -1 if no timeout.
264 */
265
266 2197780 static int get_vio_connect_timeout(MYSQL *mysql) {
267 int timeout_ms;
268 uint timeout_sec;
269
270 /*
271 A timeout of 0 means no timeout. Also, the connect_timeout
272 option value is in seconds, while VIO timeouts are measured
273 in milliseconds. Hence, check for a possible overflow. In
274 case of overflow, set to no timeout.
275 */
276 2197780 timeout_sec = mysql->options.connect_timeout;
277
278
3/4
✓ Branch 0 taken 1962775 times.
✓ Branch 1 taken 235005 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1962775 times.
2197780 if (!timeout_sec || (timeout_sec > INT_MAX / 1000))
279 235005 timeout_ms = -1;
280 else
281 1962775 timeout_ms = (int)(timeout_sec * 1000);
282
283 2197780 return timeout_ms;
284 }
285
286 #ifdef _WIN32
287
288 /**
289 Convert the connect timeout option to a timeout value for WIN32
290 synchronization functions.
291
292 @remark Specific for WIN32 connection methods shared memory and
293 named pipe.
294
295 @param mysql Connection handle (client side).
296
297 @return The timeout value in milliseconds, or INFINITE if no timeout.
298 */
299
300 static DWORD get_win32_connect_timeout(MYSQL *mysql) {
301 DWORD timeout_ms;
302 uint timeout_sec;
303
304 /*
305 A timeout of 0 means no timeout. Also, the connect_timeout
306 option value is in seconds, while WIN32 timeouts are in
307 milliseconds. Hence, check for a possible overflow. In case
308 of overflow, set to no timeout.
309 */
310 timeout_sec = mysql->options.connect_timeout;
311
312 if (!timeout_sec || (timeout_sec > INT_MAX / 1000))
313 timeout_ms = INFINITE;
314 else
315 timeout_ms = (DWORD)(timeout_sec * 1000);
316
317 return timeout_ms;
318 }
319
320 #endif
321
322 /**
323 Set the internal error message to mysql handler
324
325 @param mysql connection handle (client side)
326 @param errcode CR_ error code, passed to ER macro to get
327 error text
328 @param sqlstate SQL standard sqlstate
329 */
330
331 21891 void set_mysql_error(MYSQL *mysql, int errcode, const char *sqlstate) {
332 NET *net;
333
1/2
✓ Branch 0 taken 21891 times.
✗ Branch 1 not taken.
21891 DBUG_TRACE;
334
3/8
✓ Branch 0 taken 21891 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21891 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 21891 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
21891 DBUG_PRINT("enter", ("error :%d '%s'", errcode, ER_CLIENT(errcode)));
335
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21891 times.
21891 assert(mysql != nullptr);
336
337
1/2
✓ Branch 0 taken 21891 times.
✗ Branch 1 not taken.
21891 if (mysql) {
338 21891 net = &mysql->net;
339 21891 net->last_errno = errcode;
340 21891 my_stpcpy(net->last_error, ER_CLIENT(errcode));
341 21891 my_stpcpy(net->sqlstate, sqlstate);
342
2/8
✓ Branch 0 taken 13402 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 13402 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
13402 MYSQL_TRACE(ERROR, mysql, ());
343 } else {
344 mysql_server_last_errno = errcode;
345 my_stpcpy(mysql_server_last_error, ER_CLIENT(errcode));
346 }
347 21891 }
348
349 /**
350 Is this NET instance initialized?
351 @c my_net_init() and net_end()
352 */
353
354 1533 static bool my_net_is_inited(NET *net) { return net->buff != nullptr; }
355
356 /**
357 Clear possible error state of struct NET
358
359 @param net clear the state of the argument
360 */
361
362 31036561 void net_clear_error(NET *net) {
363 31036561 net->last_errno = 0;
364 31036561 net->last_error[0] = '\0';
365 31036561 my_stpcpy(net->sqlstate, not_error_sqlstate);
366 31036457 }
367
368 /**
369 Set an error message on the client.
370
371 @param mysql connection handle
372 @param errcode CR_* errcode, for client errors
373 @param sqlstate SQL standard sql state, unknown_sqlstate for the
374 majority of client errors.
375 @param format error message template, in sprintf format
376 @param ... variable number of arguments
377 */
378
379 1683307 void set_mysql_extended_error(MYSQL *mysql, int errcode, const char *sqlstate,
380 const char *format, ...) {
381 NET *net;
382 va_list args;
383
1/2
✓ Branch 0 taken 1683307 times.
✗ Branch 1 not taken.
1683307 DBUG_TRACE;
384
3/8
✓ Branch 0 taken 1683307 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1683307 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1683307 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1683307 DBUG_PRINT("enter", ("error :%d '%s'", errcode, format));
385
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1683307 times.
1683307 assert(mysql != nullptr);
386
387 1683307 net = &mysql->net;
388 1683307 net->last_errno = errcode;
389 1683307 va_start(args, format);
390 1683307 vsnprintf(net->last_error, sizeof(net->last_error) - 1, format, args);
391 1683307 va_end(args);
392 1683307 my_stpcpy(net->sqlstate, sqlstate);
393
394
2/8
✓ Branch 0 taken 1682065 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1682065 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1682065 MYSQL_TRACE(ERROR, mysql, ());
395 1683307 }
396
397 /*
398 Create a named pipe connection
399 */
400
401 #ifdef _WIN32
402
403 static HANDLE create_named_pipe(MYSQL *mysql, DWORD connect_timeout,
404 const char **arg_host,
405 const char **arg_unix_socket) {
406 HANDLE hPipe = INVALID_HANDLE_VALUE;
407 char pipe_name[1024];
408 DWORD dwMode;
409 int i;
410 const char *host = *arg_host, *unix_socket = *arg_unix_socket;
411
412 if (!unix_socket || (unix_socket)[0] == 0x00) unix_socket = mysql_unix_port;
413 if (!host || !strcmp(host, LOCAL_HOST)) host = LOCAL_HOST_NAMEDPIPE;
414
415 pipe_name[sizeof(pipe_name) - 1] = 0; /* Safety if too long string */
416 strxnmov(pipe_name, sizeof(pipe_name) - 1, "\\\\.\\pipe\\", unix_socket,
417 NullS);
418
419 DBUG_PRINT("info", ("Server name: '%s'. Named Pipe: %s", host, unix_socket));
420
421 for (i = 0; i < 100; i++) /* Don't retry forever */
422 {
423 if ((hPipe = CreateFile(pipe_name,
424 FILE_READ_ATTRIBUTES | FILE_READ_DATA |
425 FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA,
426 0, NULL, OPEN_EXISTING,
427 FILE_FLAG_OVERLAPPED | SECURITY_SQOS_PRESENT |
428 SECURITY_IDENTIFICATION,
429 NULL)) != INVALID_HANDLE_VALUE)
430 break;
431 if (GetLastError() != ERROR_PIPE_BUSY) {
432 set_mysql_extended_error(mysql, CR_NAMEDPIPEOPEN_ERROR, unknown_sqlstate,
433 ER_CLIENT(CR_NAMEDPIPEOPEN_ERROR), host,
434 unix_socket, (ulong)GetLastError());
435 return INVALID_HANDLE_VALUE;
436 }
437 /* wait for for an other instance */
438 if (!WaitNamedPipe(pipe_name, connect_timeout)) {
439 set_mysql_extended_error(mysql, CR_NAMEDPIPEWAIT_ERROR, unknown_sqlstate,
440 ER_CLIENT(CR_NAMEDPIPEWAIT_ERROR), host,
441 unix_socket, (ulong)GetLastError());
442 return INVALID_HANDLE_VALUE;
443 }
444 }
445 if (hPipe == INVALID_HANDLE_VALUE) {
446 set_mysql_extended_error(mysql, CR_NAMEDPIPEOPEN_ERROR, unknown_sqlstate,
447 ER_CLIENT(CR_NAMEDPIPEOPEN_ERROR), host,
448 unix_socket, (ulong)GetLastError());
449 return INVALID_HANDLE_VALUE;
450 }
451 dwMode = PIPE_READMODE_BYTE | PIPE_WAIT;
452 if (!SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL)) {
453 CloseHandle(hPipe);
454 set_mysql_extended_error(mysql, CR_NAMEDPIPESETSTATE_ERROR,
455 unknown_sqlstate,
456 ER_CLIENT(CR_NAMEDPIPESETSTATE_ERROR), host,
457 unix_socket, (ulong)GetLastError());
458 return INVALID_HANDLE_VALUE;
459 }
460 *arg_host = host;
461 *arg_unix_socket = unix_socket; /* connect arg */
462 return (hPipe);
463 }
464 #endif
465
466 /*
467 Create new shared memory connection, return handler of connection
468
469 @param mysql Pointer of mysql structure
470 @param net Pointer of net structure
471 @param connect_timeout Timeout of connection (in milliseconds)
472
473 @return HANDLE to the shared memory area.
474 */
475
476 #if defined(_WIN32)
477 static HANDLE create_shared_memory(MYSQL *mysql, NET *net,
478 DWORD connect_timeout) {
479 ulong smem_buffer_length = shared_memory_buffer_length + 4;
480 /*
481 event_connect_request is event object for start connection actions
482 event_connect_answer is event object for confirm, that server put data
483 handle_connect_file_map is file-mapping object, use for create shared
484 memory
485 handle_connect_map is pointer on shared memory
486 handle_map is pointer on shared memory for client
487 event_server_wrote,
488 event_server_read,
489 event_client_wrote,
490 event_client_read are events for transfer data between server and client
491 handle_file_map is file-mapping object, use for create shared memory
492 */
493 HANDLE event_connect_request = NULL;
494 HANDLE event_connect_answer = NULL;
495 HANDLE handle_connect_file_map = NULL;
496 char *handle_connect_map = NULL;
497
498 char *handle_map = NULL;
499 HANDLE event_server_wrote = NULL;
500 HANDLE event_server_read = NULL;
501 HANDLE event_client_wrote = NULL;
502 HANDLE event_client_read = NULL;
503 HANDLE event_conn_closed = NULL;
504 HANDLE handle_file_map = NULL;
505 HANDLE connect_named_mutex = NULL;
506 ulong connect_number;
507 char connect_number_char[22], *p;
508 char *tmp = NULL;
509 char *suffix_pos = NULL;
510 DWORD error_allow = 0;
511 DWORD error_code = 0;
512 DWORD event_access_rights = SYNCHRONIZE | EVENT_MODIFY_STATE;
513 char *shared_memory_base_name = mysql->options.shared_memory_base_name;
514 static const char *name_prefixes[] = {"", "Global\\"};
515 const char *prefix;
516
517 /*
518 If this is NULL, somebody freed the MYSQL* options. mysql_close()
519 is a good candidate. We don't just silently (re)set it to
520 def_shared_memory_base_name as that would create really confusing/buggy
521 behavior if the user passed in a different name on the command-line or
522 in a my.cnf.
523 */
524 assert(shared_memory_base_name != NULL);
525
526 /*
527 get enough space base-name + '_' + longest suffix we might ever send
528 */
529 if (!(tmp = (char *)my_malloc(key_memory_create_shared_memory,
530 strlen(shared_memory_base_name) + 32L,
531 MYF(MY_FAE))))
532 goto err;
533
534 /*
535 The name of event and file-mapping events create agree next rule:
536 shared_memory_base_name+unique_part
537 Where:
538 shared_memory_base_name is unique value for each server
539 unique_part is uniquel value for each object (events and file-mapping)
540 */
541 for (size_t i = 0; i < array_elements(name_prefixes); i++) {
542 prefix = name_prefixes[i];
543 suffix_pos = strxmov(tmp, prefix, shared_memory_base_name, "_", NullS);
544 my_stpcpy(suffix_pos, "CONNECT_REQUEST");
545 event_connect_request = OpenEvent(event_access_rights, false, tmp);
546 if (event_connect_request) {
547 break;
548 }
549 }
550 if (!event_connect_request) {
551 error_allow = CR_SHARED_MEMORY_CONNECT_REQUEST_ERROR;
552 goto err;
553 }
554 assert(suffix_pos != nullptr);
555 my_stpcpy(suffix_pos, "CONNECT_ANSWER");
556 if (!(event_connect_answer = OpenEvent(event_access_rights, false, tmp))) {
557 error_allow = CR_SHARED_MEMORY_CONNECT_ANSWER_ERROR;
558 goto err;
559 }
560 my_stpcpy(suffix_pos, "CONNECT_DATA");
561 if (!(handle_connect_file_map =
562 OpenFileMapping(FILE_MAP_WRITE, false, tmp))) {
563 error_allow = CR_SHARED_MEMORY_CONNECT_FILE_MAP_ERROR;
564 goto err;
565 }
566 if (!(handle_connect_map = static_cast<char *>(MapViewOfFile(
567 handle_connect_file_map, FILE_MAP_WRITE, 0, 0, sizeof(DWORD))))) {
568 error_allow = CR_SHARED_MEMORY_CONNECT_MAP_ERROR;
569 goto err;
570 }
571
572 my_stpcpy(suffix_pos, "CONNECT_NAMED_MUTEX");
573 connect_named_mutex = OpenMutex(SYNCHRONIZE, false, tmp);
574 if (connect_named_mutex == NULL) {
575 error_allow = CR_SHARED_MEMORY_CONNECT_SET_ERROR;
576 goto err;
577 }
578
579 if (WaitForSingleObject(connect_named_mutex, connect_timeout) !=
580 WAIT_OBJECT_0) {
581 error_allow = CR_SHARED_MEMORY_CONNECT_ABANDONED_ERROR;
582 goto err;
583 }
584
585 /* Send to server request of connection */
586 if (!SetEvent(event_connect_request)) {
587 error_allow = CR_SHARED_MEMORY_CONNECT_SET_ERROR;
588 goto err;
589 }
590
591 /* Wait of answer from server */
592 if (WaitForSingleObject(event_connect_answer, connect_timeout) !=
593 WAIT_OBJECT_0) {
594 error_allow = CR_SHARED_MEMORY_CONNECT_ABANDONED_ERROR;
595 goto err;
596 }
597
598 /* Get number of connection */
599 connect_number = uint4korr(handle_connect_map); /*WAX2*/
600
601 ReleaseMutex(connect_named_mutex);
602 CloseHandle(connect_named_mutex);
603 connect_named_mutex = NULL;
604
605 p = longlong10_to_str(connect_number, connect_number_char, 10);
606
607 /*
608 The name of event and file-mapping events create agree next rule:
609 shared_memory_base_name+unique_part+number_of_connection
610
611 Where:
612 shared_memory_base_name is uniquel value for each server
613 unique_part is uniquel value for each object (events and file-mapping)
614 number_of_connection is number of connection between server and client
615 */
616 suffix_pos = strxmov(tmp, prefix, shared_memory_base_name, "_",
617 connect_number_char, "_", NullS);
618 my_stpcpy(suffix_pos, "DATA");
619 if ((handle_file_map = OpenFileMapping(FILE_MAP_WRITE, false, tmp)) == NULL) {
620 error_allow = CR_SHARED_MEMORY_FILE_MAP_ERROR;
621 goto err2;
622 }
623 if ((handle_map = static_cast<char *>(MapViewOfFile(
624 handle_file_map, FILE_MAP_WRITE, 0, 0, smem_buffer_length))) ==
625 NULL) {
626 error_allow = CR_SHARED_MEMORY_MAP_ERROR;
627 goto err2;
628 }
629
630 my_stpcpy(suffix_pos, "SERVER_WROTE");
631 if ((event_server_wrote = OpenEvent(event_access_rights, false, tmp)) ==
632 NULL) {
633 error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
634 goto err2;
635 }
636
637 my_stpcpy(suffix_pos, "SERVER_READ");
638 if ((event_server_read = OpenEvent(event_access_rights, false, tmp)) ==
639 NULL) {
640 error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
641 goto err2;
642 }
643
644 my_stpcpy(suffix_pos, "CLIENT_WROTE");
645 if ((event_client_wrote = OpenEvent(event_access_rights, false, tmp)) ==
646 NULL) {
647 error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
648 goto err2;
649 }
650
651 my_stpcpy(suffix_pos, "CLIENT_READ");
652 if ((event_client_read = OpenEvent(event_access_rights, false, tmp)) ==
653 NULL) {
654 error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
655 goto err2;
656 }
657
658 my_stpcpy(suffix_pos, "CONNECTION_CLOSED");
659 if ((event_conn_closed = OpenEvent(event_access_rights, false, tmp)) ==
660 NULL) {
661 error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
662 goto err2;
663 }
664 /*
665 Set event that server should send data
666 */
667 SetEvent(event_server_read);
668
669 err2:
670 if (error_allow == 0) {
671 net->vio = vio_new_win32shared_memory(
672 handle_file_map, handle_map, event_server_wrote, event_server_read,
673 event_client_wrote, event_client_read, event_conn_closed);
674 } else {
675 error_code = GetLastError();
676 if (event_server_read) CloseHandle(event_server_read);
677 if (event_server_wrote) CloseHandle(event_server_wrote);
678 if (event_client_read) CloseHandle(event_client_read);
679 if (event_client_wrote) CloseHandle(event_client_wrote);
680 if (event_conn_closed) CloseHandle(event_conn_closed);
681 if (handle_map) UnmapViewOfFile(handle_map);
682 if (handle_file_map) CloseHandle(handle_file_map);
683 }
684 err:
685 my_free(tmp);
686 if (error_allow) error_code = GetLastError();
687 if (event_connect_request) CloseHandle(event_connect_request);
688 if (event_connect_answer) CloseHandle(event_connect_answer);
689 if (handle_connect_map) UnmapViewOfFile(handle_connect_map);
690 if (handle_connect_file_map) CloseHandle(handle_connect_file_map);
691 if (error_allow) {
692 if (connect_named_mutex) {
693 ReleaseMutex(connect_named_mutex);
694 CloseHandle(connect_named_mutex);
695 }
696
697 if (error_allow == CR_SHARED_MEMORY_EVENT_ERROR)
698 set_mysql_extended_error(mysql, error_allow, unknown_sqlstate,
699 ER_CLIENT(error_allow), suffix_pos, error_code);
700 else
701 set_mysql_extended_error(mysql, error_allow, unknown_sqlstate,
702 ER_CLIENT(error_allow), error_code);
703 return (INVALID_HANDLE_VALUE);
704 }
705 return (handle_map);
706 }
707 #endif
708
709 /*
710 Free all memory acquired to store state change information.
711 */
712 43464991 static void free_state_change_info(MYSQL_EXTENSION *ext) {
713 STATE_INFO *info;
714 int i;
715
716
1/2
✓ Branch 0 taken 43465134 times.
✗ Branch 1 not taken.
43464991 if (ext)
717 43465134 info = &ext->state_change;
718 else
719 return;
720
721
2/2
✓ Branch 0 taken 260790171 times.
✓ Branch 1 taken 43464930 times.
304255101 for (i = SESSION_TRACK_SYSTEM_VARIABLES; i <= SESSION_TRACK_END; i++) {
722
2/2
✓ Branch 0 taken 604395 times.
✓ Branch 1 taken 260185644 times.
260790171 if (list_length(info->info_list[i].head_node) != 0) {
723 604395 list_free(info->info_list[i].head_node, (uint)0);
724 }
725 }
726 43464930 memset(info, 0, sizeof(STATE_INFO));
727 }
728
729 /**
730 Helper function to check if the buffer has at least bytes remaining
731
732 If the buffer is too small it raises CR_MALFORMED_PACKET_ERROR.
733
734 @param mysql the handle that has the buffer
735 @param packet the current position in the buffer
736 @param packet_length the size of the packet
737 @param bytes the bytes that we want available
738 @retval true the buffer has that many bytes
739 @retval false the buffer has less bytes remaining
740 */
741 89073057 inline bool buffer_check_remaining(MYSQL *mysql, uchar *packet,
742 ulong packet_length, size_t bytes) {
743 size_t remaining_bytes;
744 /* Check to avoid underflow */
745
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 89073057 times.
89073057 if (packet_length < (ulong)(packet - mysql->net.read_pos)) {
746 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
747 return false;
748 }
749 89073057 remaining_bytes = packet_length - (packet - mysql->net.read_pos);
750
2/2
✓ Branch 0 taken 43 times.
✓ Branch 1 taken 89073014 times.
89073057 if (remaining_bytes < bytes) {
751 43 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
752 43 return false;
753 }
754 89073014 return true;
755 }
756
757 /*
758 Helper function to safely read a variable size from a buffer.
759 If the buffer is too small, it raises CR_MALFORMED_PACKET_ERROR
760 and sets is_error to true.
761 Otherwise it sets is_error to false and calls @ref inet_field_length_ll.
762
763 @sa @ref net_field_length_ll
764
765 @param mysql the handle to return an error in
766 @param [in,out] packet pointer to the buffer to read the length from
767 @param packet_length remaining bytes in packet
768 @param [out] is_error set to true if the buffer contains no room for a
769 full length, false otherwise.
770 @return the size read.
771 */
772 45472631 inline my_ulonglong net_field_length_ll_safe(MYSQL *mysql, uchar **packet,
773 ulong packet_length,
774 bool *is_error) {
775 45472631 size_t sizeof_len = net_field_length_size(*packet);
776
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 45473156 times.
45472951 DBUG_EXECUTE_IF("simulate_bad_packet",
777 { *packet = *packet + packet_length + 1000000L; });
778
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 45473101 times.
45473156 if (!buffer_check_remaining(mysql, *packet, packet_length, sizeof_len)) {
779 *is_error = true;
780 return 0;
781 }
782
783 45473101 *is_error = false;
784 45473101 return net_field_length_ll(packet);
785 }
786
787 /**
788 Read Ok packet along with the server state change information.
789 */
790 20381922 void read_ok_ex(MYSQL *mysql, ulong length) {
791 size_t total_len, len;
792 uchar *pos, *saved_pos;
793 my_ulonglong affected_rows, insert_id;
794 char *db;
795 char *data_str;
796
797 CHARSET_INFO *saved_cs;
798 bool is_charset;
799
800 20381922 STATE_INFO *info = nullptr;
801 20381922 LIST *element = nullptr;
802 20381922 LEX_STRING *data = nullptr;
803 bool is_error;
804
805 20381922 pos = mysql->net.read_pos + 1;
806
807
1/2
✓ Branch 0 taken 20381939 times.
✗ Branch 1 not taken.
20381922 affected_rows = net_field_length_ll_safe(mysql, &pos, length,
808 &is_error); /* affected rows */
809
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20381939 times.
20381939 if (is_error) return;
810 insert_id =
811
1/2
✓ Branch 0 taken 20382110 times.
✗ Branch 1 not taken.
20381939 net_field_length_ll_safe(mysql, &pos, length, &is_error); /* insert id */
812
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20382110 times.
20382110 if (is_error) return;
813
814 /*
815 The following check ensures that we skip the assignment for the
816 above read fields (i.e. affected_rows and insert_id) wherein the
817 EOF packets are deprecated and the server sends OK packet instead
818 with a packet header of 0xFE (254) to identify it as an EOF packet.
819 We ignore this assignment as the valid contents of EOF packet include
820 packet marker, server status and warning count only. However, we would
821 assign these values to the connection handle if it was an OK packet
822 with a packet header of 0x00.
823 */
824
825
1/2
✓ Branch 0 taken 20382123 times.
✗ Branch 1 not taken.
20382110 if (!((mysql->server_capabilities & CLIENT_DEPRECATE_EOF) &&
826
2/2
✓ Branch 0 taken 9926026 times.
✓ Branch 1 taken 10456097 times.
20382123 mysql->net.read_pos[0] == 254)) {
827 9926013 mysql->affected_rows = affected_rows;
828 9926013 mysql->insert_id = insert_id;
829
830
3/8
✓ Branch 0 taken 9926030 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9926020 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9926020 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
9926013 DBUG_PRINT("info", ("affected_rows: %lu insert_id: %lu",
831 (ulong)mysql->affected_rows, (ulong)mysql->insert_id));
832 }
833
834
2/4
✓ Branch 0 taken 20382073 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 20382073 times.
20382117 if (!buffer_check_remaining(mysql, pos, length, 2)) return;
835 /* server status */
836 20382073 mysql->server_status = uint2korr(pos);
837 20381892 pos += 2;
838
839
1/2
✓ Branch 0 taken 20381892 times.
✗ Branch 1 not taken.
20381892 if (protocol_41(mysql)) {
840
3/4
✓ Branch 0 taken 20381985 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 43 times.
✓ Branch 3 taken 20381942 times.
20381892 if (!buffer_check_remaining(mysql, pos, length, 2)) return;
841 20381942 mysql->warning_count = uint2korr(pos);
842 20382041 pos += 2;
843 } else
844 mysql->warning_count = 0; /* MySQL 4.0 protocol */
845
846
3/8
✓ Branch 0 taken 20382045 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20382048 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 20382048 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
20382041 DBUG_PRINT("info", ("status: %u warning_count: %u", mysql->server_status,
847 mysql->warning_count));
848
1/2
✓ Branch 0 taken 20382062 times.
✗ Branch 1 not taken.
20382062 if (mysql->server_capabilities & CLIENT_SESSION_TRACK) {
849
1/2
✓ Branch 0 taken 20381935 times.
✗ Branch 1 not taken.
20382062 free_state_change_info(static_cast<MYSQL_EXTENSION *>(mysql->extension));
850
851
2/2
✓ Branch 0 taken 2126908 times.
✓ Branch 1 taken 18255027 times.
20381935 if (pos < mysql->net.read_pos + length) {
852 /* get the info field */
853 size_t length_msg_member =
854
1/2
✓ Branch 0 taken 2126946 times.
✗ Branch 1 not taken.
2126908 (size_t)net_field_length_ll_safe(mysql, &pos, length, &is_error);
855
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2126946 times.
2126946 if (is_error) return;
856
2/4
✓ Branch 0 taken 2126940 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2126940 times.
2126946 if (!buffer_check_remaining(mysql, pos, length, length_msg_member))
857 return;
858
2/2
✓ Branch 0 taken 1450264 times.
✓ Branch 1 taken 676676 times.
2126940 mysql->info = (length_msg_member ? (char *)pos : nullptr);
859 2126940 pos += (length_msg_member);
860
861 /* read session state changes info */
862
2/2
✓ Branch 0 taken 605248 times.
✓ Branch 1 taken 1521692 times.
2126940 if (mysql->server_status & SERVER_SESSION_STATE_CHANGED) {
863 605248 saved_pos = pos;
864 total_len =
865
1/2
✓ Branch 0 taken 605267 times.
✗ Branch 1 not taken.
605248 (size_t)net_field_length_ll_safe(mysql, &pos, length, &is_error);
866
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 605267 times.
605267 if (is_error) return;
867 /* ensure that mysql->info is zero-terminated */
868
2/2
✓ Branch 0 taken 262 times.
✓ Branch 1 taken 605005 times.
605267 if (mysql->info) *saved_pos = 0;
869
870
2/2
✓ Branch 0 taken 633635 times.
✓ Branch 1 taken 605373 times.
1239008 while (total_len > 0) {
871 633635 saved_pos = pos;
872 my_ulonglong type =
873
1/2
✓ Branch 0 taken 633709 times.
✗ Branch 1 not taken.
633635 net_field_length_ll_safe(mysql, &pos, length, &is_error);
874
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 633709 times.
633709 if (is_error) return;
875
5/5
✓ Branch 0 taken 76167 times.
✓ Branch 1 taken 557312 times.
✓ Branch 2 taken 38 times.
✓ Branch 3 taken 108 times.
✓ Branch 4 taken 84 times.
633709 switch (type) {
876 76167 case SESSION_TRACK_SYSTEM_VARIABLES:
877 /* Move past the total length of the changed entity. */
878
1/2
✓ Branch 0 taken 76167 times.
✗ Branch 1 not taken.
76167 (void)net_field_length_ll_safe(mysql, &pos, length, &is_error);
879
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 76167 times.
76167 if (is_error) return;
880
881 /* Name of the system variable. */
882
1/2
✓ Branch 0 taken 76167 times.
✗ Branch 1 not taken.
76167 len = (size_t)net_field_length_ll_safe(mysql, &pos, length,
883 &is_error);
884
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 76167 times.
76167 if (is_error) return;
885
2/4
✓ Branch 0 taken 76167 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 76167 times.
76167 if (!buffer_check_remaining(mysql, pos, length, len)) return;
886
887
2/4
✓ Branch 0 taken 76167 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 76167 times.
76167 if (!my_multi_malloc(key_memory_MYSQL_state_change_info, MYF(0),
888 &element, sizeof(LIST), &data,
889 sizeof(LEX_STRING), &data_str, len, NullS)) {
890 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
891 return;
892 }
893
894 76167 data->str = data_str;
895 76167 memcpy(data->str, (char *)pos, len);
896 76167 data->length = len;
897 76167 pos += len;
898
899 76167 element->data = data;
900
3/8
✓ Branch 0 taken 76167 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 76167 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 76167 times.
✗ Branch 7 not taken.
76167 ADD_INFO(info, element, SESSION_TRACK_SYSTEM_VARIABLES);
901
902 /*
903 Check if the changed variable was charset. In that case we need
904 to update mysql->charset.
905 */
906
2/2
✓ Branch 0 taken 17887 times.
✓ Branch 1 taken 58280 times.
76167 if (!strncmp(data->str, "character_set_client", data->length))
907 17887 is_charset = true;
908 else
909 58280 is_charset = false;
910
911 /* Value of the system variable. */
912
1/2
✓ Branch 0 taken 76167 times.
✗ Branch 1 not taken.
76167 len = (size_t)net_field_length_ll_safe(mysql, &pos, length,
913 &is_error);
914
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 76167 times.
76167 if (is_error) return;
915
2/4
✓ Branch 0 taken 76167 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 76167 times.
76167 if (!buffer_check_remaining(mysql, pos, length, len)) return;
916
917
2/4
✓ Branch 0 taken 76167 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 76167 times.
76167 if (!my_multi_malloc(key_memory_MYSQL_state_change_info, MYF(0),
918 &element, sizeof(LIST), &data,
919 sizeof(LEX_STRING), &data_str, len, NullS)) {
920 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
921 return;
922 }
923
924 76167 data->str = data_str;
925 76167 memcpy(data->str, (char *)pos, len);
926 76167 data->length = len;
927 76167 pos += len;
928
929 76167 element->data = data;
930
3/8
✓ Branch 0 taken 76167 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 76167 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 76167 times.
✗ Branch 7 not taken.
76167 ADD_INFO(info, element, SESSION_TRACK_SYSTEM_VARIABLES);
931
932
2/2
✓ Branch 0 taken 17887 times.
✓ Branch 1 taken 58280 times.
76167 if (is_charset == 1) {
933 char charset_name[MY_CS_NAME_SIZE * 8]; // MY_CS_BUFFER_SIZE
934 size_t charset_name_length =
935 17887 std::min(data->length, sizeof(charset_name) - 1);
936 17887 saved_cs = mysql->charset;
937
938 17887 memcpy(charset_name, data->str, charset_name_length);
939 17887 charset_name[charset_name_length] = 0;
940
941
2/4
✓ Branch 0 taken 17887 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 17887 times.
17887 if (!(mysql->charset = get_charset_by_csname(
942 charset_name, MY_CS_PRIMARY, MYF(MY_WME)))) {
943 DBUG_PRINT(
944 "warning",
945 ("session tracker supplied %s is not a valid charset."
946 " Keeping the old one.",
947 charset_name));
948 mysql->charset = saved_cs;
949 }
950 }
951 76167 break;
952 557312 case SESSION_TRACK_TRANSACTION_STATE:
953 case SESSION_TRACK_TRANSACTION_CHARACTERISTICS:
954 case SESSION_TRACK_SCHEMA:
955
956 /* Move past the total length of the changed entity. */
957
1/2
✓ Branch 0 taken 557398 times.
✗ Branch 1 not taken.
557312 (void)net_field_length_ll_safe(mysql, &pos, length, &is_error);
958
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 557398 times.
557398 if (is_error) return;
959
1/2
✓ Branch 0 taken 557405 times.
✗ Branch 1 not taken.
557398 len = (size_t)net_field_length_ll_safe(mysql, &pos, length,
960 &is_error);
961
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 557405 times.
557405 if (is_error) return;
962
2/4
✓ Branch 0 taken 557402 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 557402 times.
557405 if (!buffer_check_remaining(mysql, pos, length, len)) return;
963
964
2/4
✓ Branch 0 taken 557430 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 557430 times.
557402 if (!my_multi_malloc(key_memory_MYSQL_state_change_info, MYF(0),
965 &element, sizeof(LIST), &data,
966 sizeof(LEX_STRING), &data_str, len, NullS)) {
967 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
968 return;
969 }
970
971 557430 data->str = data_str;
972 557430 memcpy(data->str, (char *)pos, len);
973 557430 data->length = len;
974 557430 pos += len;
975
976 557430 element->data = data;
977
4/8
✓ Branch 0 taken 557418 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 557425 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 557434 times.
✗ Branch 7 not taken.
557430 ADD_INFO(info, element, type);
978
979
2/2
✓ Branch 0 taken 428870 times.
✓ Branch 1 taken 128564 times.
557434 if (type == SESSION_TRACK_SCHEMA) {
980
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 428875 times.
428875 if (!(db = (char *)my_malloc(key_memory_MYSQL_state_change_info,
981
1/2
✓ Branch 0 taken 428875 times.
✗ Branch 1 not taken.
428870 data->length + 1, MYF(MY_WME)))) {
982 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
983 return;
984 }
985
986
3/4
✓ Branch 0 taken 383746 times.
✓ Branch 1 taken 45129 times.
✓ Branch 2 taken 383735 times.
✗ Branch 3 not taken.
428875 if (mysql->db) my_free(mysql->db);
987
988 428864 memcpy(db, data->str, data->length);
989 428864 db[data->length] = '\0';
990 428864 mysql->db = db;
991 }
992
993 557428 break;
994 38 case SESSION_TRACK_GTIDS:
995 /* Move past the total length of the changed entity. */
996
1/2
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
38 (void)net_field_length_ll_safe(mysql, &pos, length, &is_error);
997
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
38 if (is_error) return;
998
999 /* read (and ignore for now) the GTIDS encoding specification code
1000 */
1001
1/2
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
38 (void)net_field_length_ll_safe(mysql, &pos, length, &is_error);
1002
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
38 if (is_error) return;
1003
1004 /*
1005 For now we ignore the encoding specification, since only one
1006 is supported. In the future the decoding of what comes next
1007 depends on the specification code.
1008 */
1009
1010 /* read the length of the encoded string. */
1011
1/2
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
38 len = (size_t)net_field_length_ll_safe(mysql, &pos, length,
1012 &is_error);
1013
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
38 if (is_error) return;
1014
2/4
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 38 times.
38 if (!buffer_check_remaining(mysql, pos, length, len)) return;
1015
1016
2/4
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 38 times.
38 if (!my_multi_malloc(key_memory_MYSQL_state_change_info, MYF(0),
1017 &element, sizeof(LIST), &data,
1018 sizeof(LEX_STRING), &data_str, len, NullS)) {
1019 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
1020 return;
1021 }
1022
1023 38 data->str = data_str;
1024 38 memcpy(data->str, (char *)pos, len);
1025 38 data->length = len;
1026 38 pos += len;
1027
1028 38 element->data = data;
1029
3/8
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 38 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 38 times.
✗ Branch 7 not taken.
38 ADD_INFO(info, element, SESSION_TRACK_GTIDS);
1030 38 break;
1031 108 case SESSION_TRACK_STATE_CHANGE:
1032 /* Get the length of the boolean tracker */
1033
1/2
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
108 len = (size_t)net_field_length_ll_safe(mysql, &pos, length,
1034 &is_error);
1035
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
108 if (is_error) return;
1036
1037 /* length for boolean tracker is always 1 */
1038
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
108 assert(len == 1);
1039
2/4
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 108 times.
108 if (!buffer_check_remaining(mysql, pos, length, len)) return;
1040
1041
2/4
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 108 times.
108 if (!my_multi_malloc(key_memory_MYSQL_state_change_info, MYF(0),
1042 &element, sizeof(LIST), &data,
1043 sizeof(LEX_STRING), &data_str, len, NullS)) {
1044 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
1045 return;
1046 }
1047
1048 108 data->str = data_str;
1049 108 memcpy(data->str, (char *)pos, len);
1050 108 data->length = len;
1051 108 pos += len;
1052
1053 108 element->data = data;
1054
3/8
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 108 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 108 times.
✗ Branch 7 not taken.
108 ADD_INFO(info, element, SESSION_TRACK_STATE_CHANGE);
1055
1056 108 break;
1057 84 default:
1058
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
84 if (type > SESSION_TRACK_END) {
1059 DBUG_PRINT(
1060 "warning",
1061 ("invalid/unknown session tracker type received: %llu",
1062 (unsigned long long)type));
1063 }
1064 /*
1065 Unknown/unsupported type received, get the total length and
1066 move past it.
1067 */
1068
1069
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
84 len = (size_t)net_field_length_ll_safe(mysql, &pos, length,
1070 &is_error);
1071 if (is_error) return;
1072 pos += len;
1073 break;
1074 }
1075 633741 total_len -= (pos - saved_pos);
1076 }
1077
2/2
✓ Branch 0 taken 604285 times.
✓ Branch 1 taken 1088 times.
605373 if (info) {
1078 int itype;
1079
2/2
✓ Branch 0 taken 3625367 times.
✓ Branch 1 taken 604253 times.
4229620 for (itype = SESSION_TRACK_BEGIN; itype <= SESSION_TRACK_END;
1080 itype++) {
1081
2/2
✓ Branch 0 taken 604393 times.
✓ Branch 1 taken 3020974 times.
3625367 if (info->info_list[itype].head_node) {
1082 604361 info->info_list[itype].current_node =
1083 604361 info->info_list[itype].head_node =
1084
1/2
✓ Branch 0 taken 604361 times.
✗ Branch 1 not taken.
604393 list_reverse(info->info_list[itype].head_node);
1085 }
1086 }
1087 }
1088 }
1089 }
1090 } else if (pos < mysql->net.read_pos + length && net_field_length(&pos))
1091 mysql->info = (char *)pos;
1092 else
1093 mysql->info = nullptr;
1094 20382060 return;
1095 }
1096
1097 /* Helper for cli_safe_read and cli_safe_read_nonblocking */
1098 static ulong cli_safe_read_with_ok_complete(MYSQL *mysql, bool parse_ok,
1099 bool *is_data_packet, ulong len);
1100
1101 /**
1102 Read a packet from server in asynchronous way. This function can return
1103 without completely reading the packet, in such a case call this function
1104 again until complete packet is read.
1105
1106 @param[in] mysql connection handle
1107 @param[in] parse_ok if set to true then parse OK packet if it
1108 was sent by server
1109 @param[out] is_data_packet if set to true then the packet received
1110 was a "data packet".
1111 @param[out] res The length of the packet that was read or
1112 packet_error in case of error.
1113
1114 @retval NET_ASYNC_NOT_READY packet was not completely read
1115 @retval NET_ASYNC_COMPLETE finished reading packet
1116 */
1117 27674166 net_async_status cli_safe_read_with_ok_nonblocking(MYSQL *mysql, bool parse_ok,
1118 bool *is_data_packet,
1119 ulong *res) {
1120 27674166 NET *net = &mysql->net;
1121 27674166 ulong len = 0;
1122
1/2
✓ Branch 0 taken 27674166 times.
✗ Branch 1 not taken.
27674166 DBUG_TRACE;
1123
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 27674166 times.
27674166 assert(net->vio);
1124
1125
3/4
✓ Branch 0 taken 27674166 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27671942 times.
✓ Branch 3 taken 2224 times.
27674166 if (NET_ASYNC_NOT_READY == my_net_read_nonblocking(net, &len)) {
1126 27671942 return NET_ASYNC_NOT_READY;
1127 }
1128
1129
3/8
✓ Branch 0 taken 2224 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2224 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2224 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2224 DBUG_PRINT("info",
1130 ("total nb read: %lu, net->where_b: %lu", len, net->where_b));
1131
1132
1/2
✓ Branch 0 taken 2224 times.
✗ Branch 1 not taken.
2224 *res = cli_safe_read_with_ok_complete(mysql, parse_ok, is_data_packet, len);
1133
1134 /*
1135 In case, packet is too large or connection is lost, net_end() is called to
1136 free up net->extention. Thus return NET_ASYNC_ERROR.
1137 */
1138
4/6
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2218 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
2224 if ((*res == packet_error) && (NET_ASYNC_DATA(net) == nullptr)) {
1139 return NET_ASYNC_ERROR;
1140 }
1141 2224 return NET_ASYNC_COMPLETE;
1142 27674166 }
1143
1144 /**
1145 Its a non blocking version of cli_safe_read
1146 */
1147 27674166 net_async_status cli_safe_read_nonblocking(MYSQL *mysql, bool *is_data_packet,
1148 ulong *res) {
1149 27674166 return cli_safe_read_with_ok_nonblocking(mysql, false, is_data_packet, res);
1150 }
1151
1152 /**
1153 Read a packet from server. Give error message if socket was down
1154 or packet is an error message
1155
1156 @param[in] mysql connection handle
1157 @param[in] parse_ok if set to true then parse OK packet
1158 if it is received
1159 @param[out] is_data_packet
1160 if set to true then packet received is
1161 a "data packet", that is not OK or ERR
1162 packet or EOF in case of old servers
1163
1164 @return The length of the packet that was read or packet_error in
1165 case of error. In case of error its description is stored
1166 in mysql handle.
1167 */
1168
1169 167088532 ulong cli_safe_read_with_ok(MYSQL *mysql, bool parse_ok, bool *is_data_packet) {
1170
1/2
✓ Branch 0 taken 167089305 times.
✗ Branch 1 not taken.
167088532 DBUG_TRACE;
1171 167089305 NET *net = &mysql->net;
1172 167089305 ulong len = 0;
1173
1174
3/8
✓ Branch 0 taken 165289884 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 165289745 times.
✓ Branch 5 taken 139 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
165289864 MYSQL_TRACE(READ_PACKET, mysql, ());
1175
1176
2/2
✓ Branch 0 taken 144613557 times.
✓ Branch 1 taken 22475629 times.
167089186 if (is_data_packet) *is_data_packet = false;
1177
1178
2/4
✓ Branch 0 taken 167089193 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 167088395 times.
✗ Branch 3 not taken.
167089186 if (net->vio != nullptr) len = my_net_read(net);
1179
1/2
✓ Branch 0 taken 167089118 times.
✗ Branch 1 not taken.
334177515 return cli_safe_read_with_ok_complete(mysql, parse_ok, is_data_packet, len);
1180 167089118 }
1181
1182 167090803 ulong cli_safe_read_with_ok_complete(MYSQL *mysql, bool parse_ok,
1183 bool *is_data_packet, ulong len) {
1184 167090803 NET *net = &mysql->net;
1185
1/2
✓ Branch 0 taken 167091365 times.
✗ Branch 1 not taken.
167090803 DBUG_TRACE;
1186
1187
4/4
✓ Branch 0 taken 167071630 times.
✓ Branch 1 taken 19735 times.
✓ Branch 2 taken 141 times.
✓ Branch 3 taken 167071489 times.
167091365 if (len == packet_error || len == 0) {
1188 #ifndef NDEBUG
1189 char desc[VIO_DESCRIPTION_SIZE];
1190
1/2
✓ Branch 0 taken 19738 times.
✗ Branch 1 not taken.
19876 vio_description(net->vio, desc);
1191
3/8
✓ Branch 0 taken 19738 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19738 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 19738 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
19738 DBUG_PRINT("error",
1192 ("Wrong connection or packet. fd: %s len: %lu", desc, len));
1193 #endif // NDEBUG
1194 #ifdef MYSQL_SERVER
1195
3/4
✓ Branch 0 taken 6852 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 6850 times.
6852 if (net->vio && (net->last_errno == ER_NET_READ_INTERRUPTED))
1196 2 return packet_error;
1197 #endif /*MYSQL_SERVER*/
1198
1/2
✓ Branch 0 taken 19736 times.
✗ Branch 1 not taken.
19736 end_server(mysql);
1199
1/2
✓ Branch 0 taken 19736 times.
✗ Branch 1 not taken.
19736 set_mysql_error(mysql,
1200
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 19733 times.
19736 net->last_errno == ER_NET_PACKET_TOO_LARGE
1201 ? CR_NET_PACKET_TOO_LARGE
1202 : CR_SERVER_LOST,
1203 unknown_sqlstate);
1204 19736 return packet_error;
1205 }
1206
1207
2/8
✓ Branch 0 taken 165279073 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 165279113 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
165279052 MYSQL_TRACE(PACKET_RECEIVED, mysql, (len, net->read_pos));
1208
1209
2/2
✓ Branch 0 taken 100272 times.
✓ Branch 1 taken 166971278 times.
167071550 if (net->read_pos[0] == 255) {
1210 /*
1211 After server reprts an error, usually it is ready to accept new commands
1212 and we set stage to READY_FOR_COMMAND. This can be modified by the caller
1213 of cli_safe_read().
1214 */
1215
2/10
✓ Branch 0 taken 99664 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 99664 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
99664 MYSQL_TRACE_STAGE(mysql, READY_FOR_COMMAND);
1216
1217
1/2
✓ Branch 0 taken 100272 times.
✗ Branch 1 not taken.
100272 if (len > 3) {
1218 100272 uchar *pos = net->read_pos + 1;
1219 100272 net->last_errno = uint2korr(pos);
1220 100272 pos += 2;
1221 100272 len -= 2;
1222
4/4
✓ Branch 0 taken 99945 times.
✓ Branch 1 taken 327 times.
✓ Branch 2 taken 99885 times.
✓ Branch 3 taken 60 times.
100272 if (protocol_41(mysql) && pos[0] == '#') {
1223
1/2
✓ Branch 0 taken 99885 times.
✗ Branch 1 not taken.
99885 strmake(net->sqlstate, (char *)pos + 1, SQLSTATE_LENGTH);
1224 99885 pos += SQLSTATE_LENGTH + 1;
1225 } else {
1226 /*
1227 The SQL state hasn't been received -- it should be reset to HY000
1228 (unknown error sql state).
1229 */
1230
1231 387 my_stpcpy(net->sqlstate, unknown_sqlstate);
1232 }
1233
1234
1/2
✓ Branch 0 taken 100272 times.
✗ Branch 1 not taken.
100272 (void)strmake(net->last_error, (char *)pos,
1235 200544 std::min<ulong>(len, sizeof(net->last_error) - 1));
1236 } else
1237 set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
1238 /*
1239 Cover a protocol design error: error packet does not
1240 contain the server status. Therefore, the client has no way
1241 to find out whether there are more result sets of
1242 a multiple-result-set statement pending. Luckily, in 5.0 an
1243 error always aborts execution of a statement, wherever it is
1244 a multi-statement or a stored procedure, so it should be
1245 safe to unconditionally turn off the flag here.
1246 */
1247 100272 mysql->server_status &= ~SERVER_MORE_RESULTS_EXISTS;
1248
1249
3/8
✓ Branch 0 taken 100272 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 100272 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 100272 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
100272 DBUG_PRINT("error", ("Got error: %d/%s (%s)", net->last_errno,
1250 net->sqlstate, net->last_error));
1251 100272 return packet_error;
1252 } else {
1253 /* if it is OK packet irrespective of new/old server */
1254
2/2
✓ Branch 0 taken 12838469 times.
✓ Branch 1 taken 154132809 times.
166971278 if (net->read_pos[0] == 0) {
1255
2/2
✓ Branch 0 taken 14560 times.
✓ Branch 1 taken 12823909 times.
12838469 if (parse_ok) {
1256
1/2
✓ Branch 0 taken 14562 times.
✗ Branch 1 not taken.
14560 read_ok_ex(mysql, len);
1257 14562 return len;
1258 }
1259 }
1260 /*
1261 Now we have a data packet, unless it is OK packet starting with
1262 0xFE - we detect that case below.
1263 */
1264
2/2
✓ Branch 0 taken 144610867 times.
✓ Branch 1 taken 22345851 times.
166956718 if (is_data_packet) *is_data_packet = true;
1265 /*
1266 For a packet starting with 0xFE detect if it is OK packet or a
1267 huge data packet. Note that old servers do not send OK packets
1268 starting with 0xFE.
1269 */
1270
2/2
✓ Branch 0 taken 166574040 times.
✓ Branch 1 taken 382678 times.
166956718 if ((mysql->server_capabilities & CLIENT_DEPRECATE_EOF) &&
1271
2/2
✓ Branch 0 taken 10459607 times.
✓ Branch 1 taken 156114433 times.
166574040 (net->read_pos[0] == 254)) {
1272 /* detect huge data packet */
1273
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 10459562 times.
10459607 if (len > MAX_PACKET_LENGTH) return len;
1274 /* otherwise we have OK packet starting with 0xFE */
1275
2/2
✓ Branch 0 taken 10456114 times.
✓ Branch 1 taken 3448 times.
10459562 if (is_data_packet) *is_data_packet = false;
1276 /* parse it if requested */
1277
2/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 10459561 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
10459562 if (parse_ok) read_ok_ex(mysql, len);
1278 10459560 return len;
1279 }
1280 /* for old client detect EOF packet */
1281
2/2
✓ Branch 0 taken 382703 times.
✓ Branch 1 taken 156114408 times.
156497111 if (!(mysql->server_capabilities & CLIENT_DEPRECATE_EOF) &&
1282
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 382703 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
382703 (net->read_pos[0] == 254) && (len < 8)) {
1283 if (is_data_packet) *is_data_packet = false;
1284 }
1285 }
1286 156497111 return len;
1287 167091288 }
1288
1289 /**
1290 Read a packet from server. Give error message if connection was broken or
1291 ERR packet was received. Detect if the packet received was an OK, ERR or
1292 something else (a "data packet").
1293
1294 @param[in] mysql connection handle
1295 @param[out] is_data_packet
1296 if set to true then the packet received
1297 was a "data packet".
1298
1299 @retval The length of the packet that was read or packet_error in case of
1300 error. In case of error its description is stored in mysql handle.
1301 */
1302 167073750 ulong cli_safe_read(MYSQL *mysql, bool *is_data_packet) {
1303 167073750 return cli_safe_read_with_ok(mysql, false, is_data_packet);
1304 }
1305
1306 10453980 void free_rows(MYSQL_DATA *cur) {
1307
2/2
✓ Branch 0 taken 10380096 times.
✓ Branch 1 taken 73884 times.
10453980 if (cur) {
1308 10380096 cur->alloc->Clear();
1309 10380148 my_free(cur->alloc);
1310 10380145 my_free(cur);
1311 }
1312 10454030 }
1313
1314 19633937 bool cli_advanced_command(MYSQL *mysql, enum enum_server_command command,
1315 const uchar *header, size_t header_length,
1316 const uchar *arg, size_t arg_length, bool skip_check,
1317 MYSQL_STMT *stmt) {
1318 19633937 NET *net = &mysql->net;
1319 19633937 bool result = true;
1320
4/4
✓ Branch 0 taken 14529 times.
✓ Branch 1 taken 19619408 times.
✓ Branch 2 taken 10518 times.
✓ Branch 3 taken 4011 times.
19633937 bool stmt_skip = stmt ? stmt->state != MYSQL_STMT_INIT_DONE : false;
1321
1/2
✓ Branch 0 taken 19634185 times.
✗ Branch 1 not taken.
19633937 DBUG_TRACE;
1322
1323
4/4
✓ Branch 0 taken 19634129 times.
✓ Branch 1 taken 56 times.
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 19634095 times.
19634185 if (mysql->net.vio == nullptr || net->error == NET_ERROR_SOCKET_UNUSABLE) {
1324 /* Do reconnect if possible */
1325
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 8 times.
90 if (!mysql->reconnect) return true;
1326
6/8
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 5 times.
8 if (mysql_reconnect(mysql) || stmt_skip) return true; // reconnect failed
1327 /* reconnect succeeded */
1328
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 assert(mysql->net.vio != nullptr);
1329 }
1330
1331 /* turn off non blocking operations */
1332
3/4
✓ Branch 0 taken 19634111 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 19634095 times.
19634100 if (!vio_is_blocking(mysql->net.vio))
1333
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 vio_set_blocking_flag(mysql->net.vio, true);
1334
1335
2/2
✓ Branch 0 taken 19634110 times.
✓ Branch 1 taken 1 times.
19634111 if (mysql->status != MYSQL_STATUS_READY ||
1336
2/2
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 19634023 times.
19634110 mysql->server_status & SERVER_MORE_RESULTS_EXISTS) {
1337
3/8
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
88 DBUG_PRINT("error", ("state: %d", mysql->status));
1338
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
1339 2 return true;
1340 }
1341
1342
1/2
✓ Branch 0 taken 19633865 times.
✗ Branch 1 not taken.
19634023 net_clear_error(net);
1343 19633865 mysql->info = nullptr;
1344 19633865 mysql->affected_rows = ~(my_ulonglong)0;
1345 /*
1346 Do not check the socket/protocol buffer as the
1347 result/error/timeout of a previous command might not have been read.
1348 This can happen if a client sends a query but does not reap the result
1349 before attempting to close the connection or wait_timeout occurs on
1350 the server.
1351 */
1352
1/2
✓ Branch 0 taken 19634171 times.
✗ Branch 1 not taken.
19633865 net_clear(&mysql->net, false);
1353
1354
2/10
✓ Branch 0 taken 19549570 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 19549570 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
19549570 MYSQL_TRACE_STAGE(mysql, READY_FOR_COMMAND);
1355
4/8
✓ Branch 0 taken 19549477 times.
✓ Branch 1 taken 93 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 19549313 times.
✓ Branch 5 taken 164 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
19549570 MYSQL_TRACE(SEND_COMMAND, mysql,
1356 (command, header_length, arg_length, header, arg));
1357
1358 /*
1359 If auto-reconnect mode is enabled check if connection is still alive before
1360 sending new command. Otherwise, send() might not notice that connection was
1361 closed by the server (for example, due to KILL statement), and the fact that
1362 connection is gone will be noticed only on attempt to read command's result,
1363 when it is too late to reconnect. Note that such scenario can still occur if
1364 connection gets killed after this check but before command is sent to
1365 server. But this should be rare.
1366 */
1367
9/10
✓ Branch 0 taken 19273437 times.
✓ Branch 1 taken 360477 times.
✓ Branch 2 taken 151332 times.
✓ Branch 3 taken 19122105 times.
✓ Branch 4 taken 151332 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5180 times.
✓ Branch 7 taken 146152 times.
✓ Branch 8 taken 5180 times.
✓ Branch 9 taken 19628734 times.
19633914 if ((command != COM_QUIT) && mysql->reconnect && !vio_is_connected(net->vio))
1368 5180 net->error = NET_ERROR_SOCKET_UNUSABLE;
1369
1370
3/4
✓ Branch 0 taken 19634095 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14669 times.
✓ Branch 3 taken 19619426 times.
19633914 if (net_write_command(net, (uchar)command, header, header_length, arg,
1371 arg_length)) {
1372
3/8
✓ Branch 0 taken 14669 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14669 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 14669 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
14669 DBUG_PRINT("error",
1373 ("Can't send command to server. Error: %d", socket_errno));
1374
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14669 times.
14669 if (net->last_errno == ER_NET_PACKET_TOO_LARGE) {
1375 set_mysql_error(mysql, CR_NET_PACKET_TOO_LARGE, unknown_sqlstate);
1376 goto end;
1377 }
1378
2/2
✓ Branch 0 taken 9489 times.
✓ Branch 1 taken 5180 times.
14669 if (net->last_errno == ER_NET_ERROR_ON_WRITE) {
1379 /*
1380 Write error, try to read and see if the server gave an error
1381 before closing the connection. Most likely Unix Domain Socket.
1382 */
1383
1/2
✓ Branch 0 taken 9489 times.
✗ Branch 1 not taken.
9489 if (net->vio) {
1384
1/2
✓ Branch 0 taken 9489 times.
✗ Branch 1 not taken.
9489 my_net_set_read_timeout(net, 1);
1385 /*
1386 cli_safe_read will also set error variables in net,
1387 and we are already in error state.
1388 */
1389
3/4
✓ Branch 0 taken 9489 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9406 times.
✓ Branch 3 taken 83 times.
9489 if (cli_safe_read(mysql, nullptr) == packet_error) {
1390
2/2
✓ Branch 0 taken 9404 times.
✓ Branch 1 taken 2 times.
9406 if (!mysql->reconnect) goto end;
1391 }
1392 /* Can this happen in any other case than COM_QUIT? */
1393
3/4
✓ Branch 0 taken 83 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 83 times.
85 if (!mysql->reconnect) assert(command == COM_QUIT);
1394 }
1395 }
1396
1/2
✓ Branch 0 taken 5265 times.
✗ Branch 1 not taken.
5265 end_server(mysql);
1397
6/8
✓ Branch 0 taken 5265 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4264 times.
✓ Branch 3 taken 1001 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4264 times.
✓ Branch 6 taken 1001 times.
✓ Branch 7 taken 4264 times.
5265 if (mysql_reconnect(mysql) || stmt_skip) goto end;
1398
1399
2/8
✓ Branch 0 taken 4264 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4264 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
4264 MYSQL_TRACE(SEND_COMMAND, mysql,
1400 (command, header_length, arg_length, header, arg));
1401
2/4
✓ Branch 0 taken 4264 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4264 times.
4264 if (net_write_command(net, (uchar)command, header, header_length, arg,
1402 arg_length)) {
1403 set_mysql_error(mysql, CR_SERVER_GONE_ERROR, unknown_sqlstate);
1404 goto end;
1405 }
1406 }
1407
1408
3/8
✓ Branch 0 taken 19538971 times.
✓ Branch 1 taken 166 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 19539053 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
19539137 MYSQL_TRACE(PACKET_SENT, mysql, (header_length + arg_length));
1409
1410 #if defined(CLIENT_PROTOCOL_TRACING)
1411
7/7
✓ Branch 0 taken 3994 times.
✓ Branch 1 taken 1584 times.
✓ Branch 2 taken 357405 times.
✓ Branch 3 taken 163 times.
✓ Branch 4 taken 305 times.
✓ Branch 5 taken 41 times.
✓ Branch 6 taken 19175561 times.
19539053 switch (command) {
1412 3994 case COM_STMT_PREPARE:
1413
2/10
✓ Branch 0 taken 3994 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3994 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
3994 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_PS_DESCRIPTION);
1414 3994 break;
1415
1416 1584 case COM_STMT_FETCH:
1417
2/10
✓ Branch 0 taken 1584 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1584 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
1584 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_ROW);
1418 1584 break;
1419
1420 /*
1421 No server reply is expected after these commands so we reamin
1422 ready for the next command.
1423 */
1424 357405 case COM_STMT_SEND_LONG_DATA:
1425 case COM_STMT_CLOSE:
1426 case COM_REGISTER_SLAVE:
1427 case COM_QUIT:
1428 357405 break;
1429
1430 /*
1431 These replication commands are not supported and we bail out
1432 by pretending that connection has been closed.
1433 */
1434 163 case COM_BINLOG_DUMP:
1435 case COM_BINLOG_DUMP_GTID:
1436 case COM_TABLE_DUMP:
1437
2/8
✓ Branch 0 taken 163 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 163 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
163 MYSQL_TRACE(DISCONNECTED, mysql, ());
1438 163 break;
1439
1440 /*
1441 After COM_CHANGE_USER a regular authentication exchange
1442 is performed.
1443 */
1444 305 case COM_CHANGE_USER:
1445
2/10
✓ Branch 0 taken 305 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 305 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
305 MYSQL_TRACE_STAGE(mysql, AUTHENTICATE);
1446 305 break;
1447
1448 /*
1449 Server replies to COM_STATISTICS with a single packet
1450 containing a string with statistics information.
1451 */
1452 41 case COM_STATISTICS:
1453
2/10
✓ Branch 0 taken 41 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 41 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
41 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_PACKET);
1454 41 break;
1455
1456 /*
1457 For all other commands we expect server to send regular reply
1458 which is either OK, ERR or a result-set header.
1459 */
1460 19175561 default:
1461
3/10
✓ Branch 0 taken 19175408 times.
✓ Branch 1 taken 153 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 19175408 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
19175561 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_RESULT);
1462 19175408 break;
1463 }
1464 #endif
1465
1466 19623453 result = false;
1467
2/2
✓ Branch 0 taken 19608569 times.
✓ Branch 1 taken 14884 times.
19623453 if (!skip_check) {
1468 14881 result = ((mysql->packet_length =
1469
1/2
✓ Branch 0 taken 14881 times.
✗ Branch 1 not taken.
14884 cli_safe_read_with_ok(mysql, true, nullptr)) == packet_error
1470 ? 1
1471 : 0);
1472
1473 #if defined(CLIENT_PROTOCOL_TRACING)
1474 /*
1475 Return to READY_FOR_COMMAND protocol stage in case server reports error
1476 or sends OK packet.
1477 */
1478
4/4
✓ Branch 0 taken 2538 times.
✓ Branch 1 taken 138 times.
✓ Branch 2 taken 2494 times.
✓ Branch 3 taken 44 times.
2676 if (result || mysql->net.read_pos[0] == 0x00)
1479
2/10
✓ Branch 0 taken 2632 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2632 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
2632 MYSQL_TRACE_STAGE(mysql, READY_FOR_COMMAND);
1480 #endif
1481 }
1482
1483 19608569 end:
1484
3/8
✓ Branch 0 taken 19633981 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19634091 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 19634091 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
19633855 DBUG_PRINT("exit", ("result: %d", result));
1485 19634077 return result;
1486 19634164 }
1487
1488 13929 net_async_status cli_advanced_command_nonblocking(
1489 MYSQL *mysql, enum enum_server_command command, const uchar *header,
1490 ulong header_length, const uchar *arg, ulong arg_length, bool skip_check,
1491 MYSQL_STMT *stmt, bool *ret) {
1492 13929 NET *net = &mysql->net;
1493
2/2
✓ Branch 0 taken 13529 times.
✓ Branch 1 taken 400 times.
13929 NET_ASYNC *net_async = NET_ASYNC_DATA(net);
1494 13929 bool result = true;
1495 13929 *ret = result;
1496
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 13929 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
13929 bool stmt_skip = stmt ? stmt->state != MYSQL_STMT_INIT_DONE : false;
1497
1/2
✓ Branch 0 taken 13929 times.
✗ Branch 1 not taken.
13929 DBUG_TRACE;
1498
1/2
✓ Branch 0 taken 13929 times.
✗ Branch 1 not taken.
13929 DBUG_DUMP("sending", header, header_length);
1499
3/4
✓ Branch 0 taken 13494 times.
✓ Branch 1 taken 435 times.
✓ Branch 2 taken 13494 times.
✗ Branch 3 not taken.
13929 if (arg && arg_length) {
1500
1/2
✓ Branch 0 taken 13494 times.
✗ Branch 1 not taken.
13494 DBUG_DUMP("sending arg", arg, arg_length);
1501 }
1502
1503
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13929 times.
13929 if (mysql->net.vio == nullptr) {
1504 set_mysql_error(mysql, CR_SERVER_GONE_ERROR, unknown_sqlstate);
1505 goto end;
1506 }
1507 /**
1508 When non blocking API execution is pending and did not complete then
1509 it can result in async context to be null. In such case if user executes
1510 any other API report command out of sync error.
1511 */
1512
2/2
✓ Branch 0 taken 400 times.
✓ Branch 1 taken 13529 times.
13929 if (net_async == nullptr) {
1513
1/2
✓ Branch 0 taken 400 times.
✗ Branch 1 not taken.
400 set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
1514 400 goto end;
1515 }
1516
2/2
✓ Branch 0 taken 184 times.
✓ Branch 1 taken 13345 times.
13529 if (net_async->async_send_command_status == NET_ASYNC_SEND_COMMAND_IDLE) {
1517
3/4
✓ Branch 0 taken 184 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 171 times.
184 if (vio_is_blocking(mysql->net.vio)) {
1518
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 vio_set_blocking_flag(net->vio, false);
1519 }
1520
1521
1/2
✓ Branch 0 taken 184 times.
✗ Branch 1 not taken.
184 if (mysql->status != MYSQL_STATUS_READY ||
1522
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 184 times.
184 mysql->server_status & SERVER_MORE_RESULTS_EXISTS) {
1523 DBUG_PRINT("error", ("state: %d", mysql->status));
1524 set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
1525 return NET_ASYNC_COMPLETE;
1526 }
1527
1528
1/2
✓ Branch 0 taken 184 times.
✗ Branch 1 not taken.
184 net_clear_error(net);
1529 184 mysql->info = nullptr;
1530 184 mysql->affected_rows = ~(my_ulonglong)0;
1531 /*
1532 Do not check the socket/protocol buffer on COM_QUIT as the
1533 result of a previous command might not have been read. This
1534 can happen if a client sends a query but does not reap
1535 the result before attempting to close the connection.
1536 */
1537
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 184 times.
184 assert(command <= COM_END);
1538
1/2
✓ Branch 0 taken 184 times.
✗ Branch 1 not taken.
184 net_clear(&mysql->net, false);
1539 184 net_async->async_send_command_status = NET_ASYNC_SEND_COMMAND_WRITE_COMMAND;
1540 }
1541
1542
2/10
✓ Branch 0 taken 13529 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 13529 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
13529 MYSQL_TRACE_STAGE(mysql, READY_FOR_COMMAND);
1543
1/2
✓ Branch 0 taken 13529 times.
✗ Branch 1 not taken.
13529 if (net_async->async_send_command_status ==
1544 NET_ASYNC_SEND_COMMAND_WRITE_COMMAND) {
1545 bool err;
1546
2/8
✓ Branch 0 taken 13529 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 13529 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
13529 MYSQL_TRACE(SEND_COMMAND, mysql,
1547 (command, header_length, arg_length, header, arg));
1548
1/2
✓ Branch 0 taken 13529 times.
✗ Branch 1 not taken.
13529 net_async_status status = net_write_command_nonblocking(
1549 net, (uchar)command, header, header_length, arg, arg_length, &err);
1550
2/2
✓ Branch 0 taken 13345 times.
✓ Branch 1 taken 184 times.
13529 if (status == NET_ASYNC_NOT_READY) {
1551 13345 return NET_ASYNC_NOT_READY;
1552 }
1553
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 181 times.
184 if (err) {
1554
3/8
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
3 DBUG_PRINT("error",
1555 ("Can't send command to server. Error: %d", socket_errno));
1556
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (net->last_errno == ER_NET_PACKET_TOO_LARGE) {
1557 set_mysql_error(mysql, CR_NET_PACKET_TOO_LARGE, unknown_sqlstate);
1558 184 goto end;
1559 }
1560
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 end_server(mysql);
1561 /* reset net_async to null as its reference has been freed */
1562 3 net_async = nullptr;
1563
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (stmt_skip) goto end;
1564
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 set_mysql_error(mysql, CR_SERVER_GONE_ERROR, unknown_sqlstate);
1565 3 goto end;
1566 }
1567
2/8
✓ Branch 0 taken 181 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 181 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
181 MYSQL_TRACE(PACKET_SENT, mysql, (header_length + arg_length));
1568
1/2
✓ Branch 0 taken 181 times.
✗ Branch 1 not taken.
181 if (skip_check) {
1569 181 result = false;
1570 181 goto end;
1571 } else {
1572 net_async->async_send_command_status = NET_ASYNC_SEND_COMMAND_READ_STATUS;
1573 }
1574 }
1575
1576 if (net_async->async_send_command_status ==
1577 NET_ASYNC_SEND_COMMAND_READ_STATUS) {
1578 ulong pkt_len;
1579 net_async_status status =
1580 cli_safe_read_with_ok_nonblocking(mysql, true, nullptr, &pkt_len);
1581 if (status == NET_ASYNC_NOT_READY) {
1582 return NET_ASYNC_NOT_READY;
1583 }
1584 mysql->packet_length = pkt_len;
1585 result = (pkt_len == packet_error ? 1 : 0);
1586 #if defined(CLIENT_PROTOCOL_TRACING)
1587 /*
1588 Return to READY_FOR_COMMAND protocol stage in case server reports
1589 error or sends OK packet.
1590 */
1591 if (!result || mysql->net.read_pos[0] == 0x00)
1592 MYSQL_TRACE_STAGE(mysql, READY_FOR_COMMAND);
1593 #endif
1594 }
1595 end:
1596
2/2
✓ Branch 0 taken 181 times.
✓ Branch 1 taken 403 times.
584 if (net_async)
1597 181 net_async->async_send_command_status = NET_ASYNC_SEND_COMMAND_IDLE;
1598
3/8
✓ Branch 0 taken 584 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 584 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 584 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
584 DBUG_PRINT("exit", ("result: %d", result));
1599 584 *ret = result;
1600 584 return NET_ASYNC_COMPLETE;
1601 13929 }
1602
1603 22408648 void free_old_query(MYSQL *mysql) {
1604
1/2
✓ Branch 0 taken 22408993 times.
✗ Branch 1 not taken.
22408648 DBUG_TRACE;
1605
2/2
✓ Branch 0 taken 22389535 times.
✓ Branch 1 taken 19458 times.
22408993 if (mysql->field_alloc) {
1606
1/2
✓ Branch 0 taken 22389454 times.
✗ Branch 1 not taken.
22389535 mysql->field_alloc->Clear();
1607 }
1608 22408912 mysql->fields = nullptr;
1609 22408912 mysql->field_count = 0; /* For API */
1610 22408912 mysql->warning_count = 0;
1611 22408912 mysql->info = nullptr;
1612 22408912 }
1613
1614 /**
1615 Finish reading of a partial result set from the server in asynchronous
1616 way. This function can return without completely flushing the result set,
1617 in such a case call this function again until result set in flushed.
1618 Read OK packet in case result set is not a data packet.
1619
1620 @param[in] mysql connection handle
1621 @param[out] res true in case of protocol error, false otherwise
1622
1623 @retval NET_ASYNC_NOT_READY result set not flushed yet
1624 @retval NET_ASYNC_COMPLETE finished flushing result set
1625 */
1626 3689 static net_async_status flush_one_result_nonblocking(MYSQL *mysql, bool *res) {
1627
1/2
✓ Branch 0 taken 3689 times.
✗ Branch 1 not taken.
3689 DBUG_TRACE;
1628
1629 3689 *res = false;
1630 while (true) {
1631 ulong packet_length;
1632 bool is_data_packet;
1633
3/4
✓ Branch 0 taken 5225 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3688 times.
✓ Branch 3 taken 1537 times.
5225 if (cli_safe_read_nonblocking(mysql, &is_data_packet, &packet_length) ==
1634 NET_ASYNC_NOT_READY) {
1635 3688 return NET_ASYNC_NOT_READY;
1636 }
1637 1537 mysql->packet_length = packet_length;
1638
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1537 times.
1537 if (packet_length == packet_error) {
1639 *res = true;
1640 break;
1641 }
1642
3/4
✓ Branch 0 taken 1537 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1536 times.
1537 if (mysql->net.read_pos[0] != 0 && !is_data_packet) {
1643
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (protocol_41(mysql)) {
1644 1 uchar *pos = mysql->net.read_pos + 1;
1645
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (mysql->server_capabilities & CLIENT_DEPRECATE_EOF &&
1646
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 !is_data_packet) {
1647
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 read_ok_ex(mysql, packet_length);
1648 } else {
1649 mysql->warning_count = uint2korr(pos);
1650 pos += 2;
1651 mysql->server_status = uint2korr(pos);
1652 }
1653 1 pos += 2;
1654 }
1655 1 break;
1656 }
1657 1536 }
1658 1 return NET_ASYNC_COMPLETE;
1659 3689 }
1660
1661 /**
1662 Finish reading of a partial result set from the server.
1663 Get the EOF packet, and update mysql->status
1664 and mysql->warning_count.
1665
1666 @return true if a communication or protocol error, an error
1667 is set in this case, false otherwise.
1668 */
1669
1670 28734 static bool flush_one_result(MYSQL *mysql) {
1671 ulong packet_length;
1672 bool is_data_packet;
1673
1674
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28734 times.
28734 assert(mysql->status != MYSQL_STATUS_READY);
1675
1676 do {
1677
1/2
✓ Branch 0 taken 28922 times.
✗ Branch 1 not taken.
28922 packet_length = cli_safe_read(mysql, &is_data_packet);
1678 /*
1679 There is an error reading from the connection,
1680 or (sic!) there were no error and no
1681 data in the stream, i.e. no more data from the server.
1682 Since we know our position in the stream (somewhere in
1683 the middle of a result set), this latter case is an error too
1684 -- each result set must end with a EOF packet.
1685 cli_safe_read() has set an error for us, just return.
1686 */
1687
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28922 times.
28922 if (packet_length == packet_error) return true;
1688
4/4
✓ Branch 0 taken 183 times.
✓ Branch 1 taken 28739 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 28734 times.
28922 } while (mysql->net.read_pos[0] == 0 || is_data_packet);
1689
1690 /* Analyse final OK packet (EOF packet if it is old client) */
1691
1692
1/2
✓ Branch 0 taken 28734 times.
✗ Branch 1 not taken.
28734 if (protocol_41(mysql)) {
1693 28734 uchar *pos = mysql->net.read_pos + 1;
1694
2/4
✓ Branch 0 taken 28734 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28734 times.
✗ Branch 3 not taken.
28734 if (mysql->server_capabilities & CLIENT_DEPRECATE_EOF && !is_data_packet)
1695
1/2
✓ Branch 0 taken 28734 times.
✗ Branch 1 not taken.
28734 read_ok_ex(mysql, packet_length);
1696 else {
1697 mysql->warning_count = uint2korr(pos);
1698 pos += 2;
1699 mysql->server_status = uint2korr(pos);
1700 }
1701 28734 pos += 2;
1702 }
1703 #if defined(CLIENT_PROTOCOL_TRACING)
1704
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 28701 times.
28734 if (mysql->server_status & SERVER_MORE_RESULTS_EXISTS)
1705
2/10
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 33 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
33 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_RESULT);
1706 else
1707
2/10
✓ Branch 0 taken 28701 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 28701 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
28701 MYSQL_TRACE_STAGE(mysql, READY_FOR_COMMAND);
1708 #endif
1709 28734 return false;
1710 }
1711
1712 380523 static bool is_OK_packet(MYSQL *mysql, ulong length) {
1713
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 380503 times.
380543 return ((mysql->net.read_pos[0] == 0) ||
1714
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 ((mysql->server_capabilities & CLIENT_DEPRECATE_EOF) &&
1715
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
380543 mysql->net.read_pos[0] == 254 && length < MAX_PACKET_LENGTH));
1716 }
1717
1718 /**
1719 Helper method to check if received packet is AuthNextFactor packet.
1720
1721 @param[in] mysql connection handle
1722
1723 @retval true packet is AuthNextFactor packet
1724 @retval false if its not AuthNextFactor packet
1725 */
1726 380491 static bool is_auth_next_factor_packet(MYSQL *mysql) {
1727
2/2
✓ Branch 0 taken 363520 times.
✓ Branch 1 taken 16971 times.
744011 return ((mysql->server_capabilities & MULTI_FACTOR_AUTHENTICATION) &&
1728
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 363520 times.
744011 (mysql->net.read_pos[0] == AUTH_NEXT_FACTOR_PACKETTYPE));
1729 }
1730 /**
1731 Read a packet from network. If it's an OK packet, flush it.
1732
1733 @return true if error, false otherwise. In case of
1734 success, is_ok_packet is set to true or false,
1735 based on what we got from network.
1736 */
1737
1738 30 static bool opt_flush_ok_packet(MYSQL *mysql, bool *is_ok_packet) {
1739 bool is_data_packet;
1740
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 ulong packet_length = cli_safe_read(mysql, &is_data_packet);
1741
1742
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if (packet_length == packet_error) return true;
1743
1744 /* cli_safe_read always reads a non-empty packet. */
1745
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 assert(packet_length);
1746
1747 30 *is_ok_packet = is_OK_packet(mysql, packet_length);
1748
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 20 times.
30 if (*is_ok_packet) {
1749
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 read_ok_ex(mysql, packet_length);
1750 #if defined(CLIENT_PROTOCOL_TRACING)
1751
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (mysql->server_status & SERVER_MORE_RESULTS_EXISTS)
1752 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_RESULT);
1753 else
1754
2/10
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
10 MYSQL_TRACE_STAGE(mysql, READY_FOR_COMMAND);
1755 #endif
1756 }
1757
1758 30 return false;
1759 }
1760
1761 3689 static net_async_status cli_flush_use_result_nonblocking(MYSQL *mysql,
1762 bool flush_all_results
1763 [[maybe_unused]]) {
1764
1/2
✓ Branch 0 taken 3689 times.
✗ Branch 1 not taken.
3689 DBUG_TRACE;
1765 /*
1766 flush_all_results is only used for mysql_stmt_close, and async is not
1767 supported for that.
1768 */
1769
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3689 times.
3689 assert(!flush_all_results);
1770 bool res;
1771
1/2
✓ Branch 0 taken 3689 times.
✗ Branch 1 not taken.
7378 return flush_one_result_nonblocking(mysql, &res);
1772 3689 }
1773
1774 /*
1775 Flush result set sent from server
1776 */
1777
1778 28714 static void cli_flush_use_result(MYSQL *mysql, bool flush_all_results) {
1779 /* Clear the current execution status */
1780
1/2
✓ Branch 0 taken 28714 times.
✗ Branch 1 not taken.
28714 DBUG_TRACE;
1781
3/8
✓ Branch 0 taken 28714 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28714 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 28714 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
28714 DBUG_PRINT("warning", ("Not all packets read, clearing them"));
1782
1783
2/4
✓ Branch 0 taken 28714 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 28714 times.
28714 if (flush_one_result(mysql)) return; /* An error occurred */
1784
1785
2/2
✓ Branch 0 taken 28602 times.
✓ Branch 1 taken 112 times.
28714 if (!flush_all_results) return;
1786
1787
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 102 times.
132 while (mysql->server_status & SERVER_MORE_RESULTS_EXISTS) {
1788 bool is_ok_packet;
1789
2/4
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 30 times.
30 if (opt_flush_ok_packet(mysql, &is_ok_packet))
1790 10 return; /* An error occurred. */
1791
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 20 times.
30 if (is_ok_packet) {
1792 /*
1793 Indeed what we got from network was an OK packet, and we
1794 know that OK is the last one in a multi-result-set, so
1795 just return.
1796 */
1797 10 return;
1798 }
1799
1800 /*
1801 It's a result set, not an OK packet. A result set contains
1802 of two result set subsequences: field metadata, terminated
1803 with EOF packet, and result set data, again terminated with
1804 EOF packet. Read and flush them.
1805 */
1806
2/10
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 20 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
20 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_FIELD_DEF);
1807
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (!(mysql->server_capabilities & CLIENT_DEPRECATE_EOF)) {
1808 if (flush_one_result(mysql)) return; /* An error occurred. */
1809 } else {
1810 20 uchar *pos = (uchar *)mysql->net.read_pos;
1811
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 ulong field_count = net_field_length(&pos);
1812
2/4
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 20 times.
20 if (read_com_query_metadata(mysql, pos, field_count)) {
1813 return;
1814 } else {
1815
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 mysql->field_alloc->Clear();
1816 }
1817 }
1818
2/10
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 20 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
20 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_ROW);
1819
2/4
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 20 times.
20 if (flush_one_result(mysql)) return;
1820 }
1821
2/2
✓ Branch 0 taken 102 times.
✓ Branch 1 taken 28612 times.
28714 }
1822
1823 #ifdef _WIN32
1824 static bool is_NT(void) {
1825 char *os = getenv("OS");
1826 return (os && !strcmp(os, "Windows_NT")) ? 1 : 0;
1827 }
1828 #endif
1829
1830 #ifdef CHECK_LICENSE
1831 /**
1832 Check server side variable 'license'.
1833
1834 If the variable does not exist or does not contain 'Commercial',
1835 we're talking to non-commercial server from commercial client.
1836
1837 @retval 0 success
1838 @retval !0 network error or the server is not commercial.
1839 Error code is saved in mysql->net.last_errno.
1840 */
1841
1842 static int check_license(MYSQL *mysql) {
1843 MYSQL_ROW row;
1844 MYSQL_RES *res;
1845 NET *net = &mysql->net;
1846 static const char query[] = "SELECT @@license";
1847 static const char required_license[] = STRINGIFY_ARG(LICENSE);
1848
1849 if (mysql_real_query(mysql, query, (ulong)(sizeof(query) - 1))) {
1850 if (net->last_errno == ER_UNKNOWN_SYSTEM_VARIABLE) {
1851 set_mysql_extended_error(mysql, CR_WRONG_LICENSE, unknown_sqlstate,
1852 ER_CLIENT(CR_WRONG_LICENSE), required_license);
1853 }
1854 return 1;
1855 }
1856 if (!(res = mysql_use_result(mysql))) return 1;
1857 row = mysql_fetch_row(res);
1858 /*
1859 If no rows in result set, or column value is NULL (none of these
1860 two is ever true for server variables now), or column value
1861 mismatch, set wrong license error.
1862 */
1863 if (!net->last_errno &&
1864 (!row || !row[0] ||
1865 strncmp(row[0], required_license, sizeof(required_license)))) {
1866 set_mysql_extended_error(mysql, CR_WRONG_LICENSE, unknown_sqlstate,
1867 ER_CLIENT(CR_WRONG_LICENSE), required_license);
1868 }
1869 mysql_free_result(res);
1870 return net->last_errno;
1871 }
1872 #endif /* CHECK_LICENSE */
1873
1874 /**************************************************************************
1875 Shut down connection
1876 **************************************************************************/
1877
1878 2055632 void end_server(MYSQL *mysql) {
1879 2055632 int save_errno = errno;
1880
1/2
✓ Branch 0 taken 2055742 times.
✗ Branch 1 not taken.
2055632 DBUG_TRACE;
1881
2/2
✓ Branch 0 taken 635954 times.
✓ Branch 1 taken 1419788 times.
2055742 if (mysql->net.vio != nullptr) {
1882 #ifndef NDEBUG
1883 char desc[VIO_DESCRIPTION_SIZE];
1884
1/2
✓ Branch 0 taken 635887 times.
✗ Branch 1 not taken.
635954 vio_description(mysql->net.vio, desc);
1885
3/8
✓ Branch 0 taken 635933 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 635891 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 635891 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
635887 DBUG_PRINT("info", ("Net: %s", desc));
1886 #endif // NDEBUG
1887 #ifdef MYSQL_SERVER
1888
1/2
✓ Branch 0 taken 12498 times.
✗ Branch 1 not taken.
12499 slave_io_thread_detach_vio();
1889 #endif
1890
1/2
✓ Branch 0 taken 635935 times.
✗ Branch 1 not taken.
635890 vio_delete(mysql->net.vio);
1891 635935 mysql->net.vio = nullptr; /* Marker */
1892
1/2
✓ Branch 0 taken 635791 times.
✗ Branch 1 not taken.
635935 mysql_prune_stmt_list(mysql);
1893 }
1894
1/2
✓ Branch 0 taken 2055710 times.
✗ Branch 1 not taken.
2055579 net_end(&mysql->net);
1895 // net_extension_free(&mysql->net);
1896
1/2
✓ Branch 0 taken 2055748 times.
✗ Branch 1 not taken.
2055710 free_old_query(mysql);
1897 2055748 errno = save_errno;
1898
3/8
✓ Branch 0 taken 2043123 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2043121 times.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2043122 MYSQL_TRACE(DISCONNECTED, mysql, ());
1899 2055747 }
1900
1901 /**
1902 Frees the memory allocated for a result, set by APIs which would have
1903 returned rows.
1904
1905 @param[in] result buffer which needs to be freed
1906
1907 @retval NET_ASYNC_NOT_READY operation not complete, retry again
1908 @retval NET_ASYNC_COMPLETE operation complete
1909 */
1910 3824 net_async_status STDCALL mysql_free_result_nonblocking(MYSQL_RES *result) {
1911
1/2
✓ Branch 0 taken 3824 times.
✗ Branch 1 not taken.
3824 DBUG_TRACE;
1912
3/8
✓ Branch 0 taken 3824 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3824 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3824 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
3824 DBUG_PRINT("enter", ("mysql_res: %p", result));
1913
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3821 times.
3824 if (!result) return NET_ASYNC_COMPLETE;
1914
1915 3821 MYSQL *mysql = result->handle;
1916
2/2
✓ Branch 0 taken 3689 times.
✓ Branch 1 taken 132 times.
3821 if (mysql) {
1917
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3688 times.
3689 if (mysql->unbuffered_fetch_owner == &result->unbuffered_fetch_cancelled)
1918 1 mysql->unbuffered_fetch_owner = nullptr;
1919
1/2
✓ Branch 0 taken 3689 times.
✗ Branch 1 not taken.
3689 if (mysql->status == MYSQL_STATUS_USE_RESULT) {
1920
3/4
✓ Branch 0 taken 3689 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3688 times.
✓ Branch 3 taken 1 times.
3689 if (mysql->methods->flush_use_result_nonblocking(mysql, false) ==
1921 NET_ASYNC_NOT_READY) {
1922 3688 return NET_ASYNC_NOT_READY;
1923 }
1924 1 mysql->status = MYSQL_STATUS_READY;
1925
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (mysql->unbuffered_fetch_owner) *mysql->unbuffered_fetch_owner = true;
1926 }
1927 }
1928
1/2
✓ Branch 0 taken 133 times.
✗ Branch 1 not taken.
133 free_rows(result->data);
1929
1/2
✓ Branch 0 taken 133 times.
✗ Branch 1 not taken.
133 if (result->field_alloc) {
1930
1/2
✓ Branch 0 taken 133 times.
✗ Branch 1 not taken.
133 result->field_alloc->Clear();
1931
1/2
✓ Branch 0 taken 133 times.
✗ Branch 1 not taken.
133 my_free(result->field_alloc);
1932 }
1933
1/2
✓ Branch 0 taken 133 times.
✗ Branch 1 not taken.
133 my_free(result->row);
1934
1/2
✓ Branch 0 taken 133 times.
✗ Branch 1 not taken.
133 my_free(result);
1935
1936 133 return NET_ASYNC_COMPLETE;
1937 3824 }
1938
1939 10632075 void STDCALL mysql_free_result(MYSQL_RES *result) {
1940
1/2
✓ Branch 0 taken 10632219 times.
✗ Branch 1 not taken.
10632075 DBUG_TRACE;
1941
3/8
✓ Branch 0 taken 10632213 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10632216 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10632216 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
10632219 DBUG_PRINT("enter", ("mysql_res: %p", result));
1942
2/2
✓ Branch 0 taken 10453693 times.
✓ Branch 1 taken 178523 times.
10632216 if (result) {
1943 10453693 MYSQL *mysql = result->handle;
1944
2/2
✓ Branch 0 taken 28589 times.
✓ Branch 1 taken 10425104 times.
10453693 if (mysql) {
1945
1/2
✓ Branch 0 taken 28589 times.
✗ Branch 1 not taken.
28589 if (mysql->unbuffered_fetch_owner == &result->unbuffered_fetch_cancelled)
1946 28589 mysql->unbuffered_fetch_owner = nullptr;
1947
1/2
✓ Branch 0 taken 28589 times.
✗ Branch 1 not taken.
28589 if (mysql->status == MYSQL_STATUS_USE_RESULT) {
1948
1/2
✓ Branch 0 taken 28589 times.
✗ Branch 1 not taken.
28589 (*mysql->methods->flush_use_result)(mysql, false);
1949 28589 mysql->status = MYSQL_STATUS_READY;
1950
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28589 times.
28589 if (mysql->unbuffered_fetch_owner)
1951 *mysql->unbuffered_fetch_owner = true;
1952 }
1953 }
1954
1/2
✓ Branch 0 taken 10453703 times.
✗ Branch 1 not taken.
10453693 free_rows(result->data);
1955
2/2
✓ Branch 0 taken 10452414 times.
✓ Branch 1 taken 1289 times.
10453703 if (result->field_alloc) {
1956
1/2
✓ Branch 0 taken 10452436 times.
✗ Branch 1 not taken.
10452414 result->field_alloc->Clear();
1957
1/2
✓ Branch 0 taken 10452435 times.
✗ Branch 1 not taken.
10452436 my_free(result->field_alloc);
1958 }
1959
1/2
✓ Branch 0 taken 10453711 times.
✗ Branch 1 not taken.
10453724 my_free(result->row);
1960
1/2
✓ Branch 0 taken 10453724 times.
✗ Branch 1 not taken.
10453711 my_free(result);
1961 }
1962 10632247 }
1963
1964 /****************************************************************************
1965 Get options from my.cnf
1966 ****************************************************************************/
1967
1968 static const char *default_options[] = {"port",
1969 "socket",
1970 "compress",
1971 "password",
1972 "pipe",
1973 "timeout",
1974 "user",
1975 "init-command",
1976 "host",
1977 "database",
1978 "debug",
1979 "return-found-rows",
1980 "ssl-key",
1981 "ssl-cert",
1982 "ssl-ca",
1983 "ssl-capath",
1984 "character-sets-dir",
1985 "default-character-set",
1986 "interactive-timeout",
1987 "connect-timeout",
1988 "local-infile",
1989 "disable-local-infile",
1990 "ssl-cipher",
1991 "max-allowed-packet",
1992 "protocol",
1993 "shared-memory-base-name",
1994 "multi-results",
1995 "multi-statements",
1996 "multi-queries",
1997 "report-data-truncation",
1998 "plugin-dir",
1999 "default-auth",
2000 "bind-address",
2001 "ssl-crl",
2002 "ssl-crlpath",
2003 "enable-cleartext-plugin",
2004 "tls-version",
2005 "ssl_mode",
2006 "optional-resultset-metadata",
2007 "ssl-fips-mode",
2008 "tls-ciphersuites",
2009 NullS};
2010 enum option_id {
2011 OPT_port = 1,
2012 OPT_socket,
2013 OPT_compress,
2014 OPT_password,
2015 OPT_pipe,
2016 OPT_timeout,
2017 OPT_user,
2018 OPT_init_command,
2019 OPT_host,
2020 OPT_database,
2021 OPT_debug,
2022 OPT_return_found_rows,
2023 OPT_ssl_key,
2024 OPT_ssl_cert,
2025 OPT_ssl_ca,
2026 OPT_ssl_capath,
2027 OPT_character_sets_dir,
2028 OPT_default_character_set,
2029 OPT_interactive_timeout,
2030 OPT_connect_timeout,
2031 OPT_local_infile,
2032 OPT_disable_local_infile,
2033 OPT_ssl_cipher,
2034 OPT_max_allowed_packet,
2035 OPT_protocol,
2036 OPT_shared_memory_base_name,
2037 OPT_multi_results,
2038 OPT_multi_statements,
2039 OPT_multi_queries,
2040 OPT_report_data_truncation,
2041 OPT_plugin_dir,
2042 OPT_default_auth,
2043 OPT_bind_address,
2044 OPT_ssl_crl,
2045 OPT_ssl_crlpath,
2046 OPT_enable_cleartext_plugin,
2047 OPT_tls_version,
2048 OPT_ssl_mode,
2049 OPT_optional_resultset_metadata,
2050 OPT_ssl_fips_mode,
2051 OPT_tls_ciphersuites,
2052 OPT_keep_this_one_last
2053 };
2054
2055 static TYPELIB option_types = {array_elements(default_options) - 1, "options",
2056 default_options, nullptr};
2057
2058 const char *sql_protocol_names_lib[] = {"TCP", "SOCKET", "PIPE", "MEMORY",
2059 NullS};
2060 TYPELIB sql_protocol_typelib = {array_elements(sql_protocol_names_lib) - 1, "",
2061 sql_protocol_names_lib, nullptr};
2062
2063 6 static int add_init_command(struct st_mysql_options *options, const char *cmd) {
2064 char *tmp;
2065
2066
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (!options->init_commands) {
2067
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 void *rawmem = my_malloc(key_memory_mysql_options,
2068 sizeof(Init_commands_array), MYF(MY_WME));
2069
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!rawmem) return 1;
2070 6 options->init_commands =
2071
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 new (rawmem) Init_commands_array(key_memory_mysql_options);
2072 }
2073
2074
3/6
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
12 if (!(tmp = my_strdup(key_memory_mysql_options, cmd, MYF(MY_WME))) ||
2075
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
6 options->init_commands->push_back(tmp)) {
2076 my_free(tmp);
2077 return 1;
2078 }
2079
2080 6 return 0;
2081 }
2082
2083 834432 static char *set_ssl_option_unpack_path(const char *arg) {
2084 834432 char *opt_var = nullptr;
2085
2/2
✓ Branch 0 taken 1335 times.
✓ Branch 1 taken 833097 times.
834432 if (arg) {
2086 char *buff =
2087 1335 (char *)my_malloc(key_memory_mysql_options, FN_REFLEN + 1, MYF(MY_WME));
2088 1335 unpack_filename(buff, arg);
2089 1335 opt_var = my_strdup(key_memory_mysql_options, buff, MYF(MY_WME));
2090 1335 my_free(buff);
2091 }
2092 834435 return opt_var;
2093 }
2094
2095 void mysql_read_default_options(struct st_mysql_options *options,
2096 const char *filename, const char *group) {
2097 int argc;
2098 char *argv_buff[1], **argv;
2099 const char *groups[3];
2100 DBUG_TRACE;
2101 DBUG_PRINT("enter",
2102 ("file: %s group: %s", filename, group ? group : "NULL"));
2103
2104 static_assert(OPT_keep_this_one_last == array_elements(default_options),
2105 "OPT_keep_this_one_last needs to be the last element.");
2106
2107 argc = 1;
2108 argv = argv_buff;
2109 argv_buff[0] = const_cast<char *>("client");
2110 groups[0] = "client";
2111 groups[1] = group;
2112 groups[2] = nullptr;
2113
2114 MEM_ROOT alloc{PSI_NOT_INSTRUMENTED, 512};
2115 my_load_defaults(filename, groups, &argc, &argv, &alloc, nullptr);
2116 if (argc != 1) /* If some default option */
2117 {
2118 char **option = argv;
2119 while (*++option) {
2120 if (my_getopt_is_args_separator(option[0])) /* skip arguments separator */
2121 continue;
2122 /* DBUG_PRINT("info",("option: %s",option[0])); */
2123 if (option[0][0] == '-' && option[0][1] == '-') {
2124 char *end = strchr(*option, '=');
2125 char *opt_arg = nullptr;
2126 if (end != nullptr) {
2127 opt_arg = end + 1;
2128 *end = 0; /* Remove '=' */
2129 }
2130 /* Change all '_' in variable name to '-' */
2131 for (end = *option; end != nullptr; end = strchr(end, '_')) *end = '-';
2132 switch (find_type(*option + 2, &option_types, FIND_TYPE_BASIC)) {
2133 case OPT_port:
2134 if (opt_arg) options->port = atoi(opt_arg);
2135 break;
2136 case OPT_socket:
2137 if (opt_arg) {
2138 my_free(options->unix_socket);
2139 options->unix_socket =
2140 my_strdup(key_memory_mysql_options, opt_arg, MYF(MY_WME));
2141 }
2142 break;
2143 case OPT_compress:
2144 options->compress = true;
2145 options->client_flag |= CLIENT_COMPRESS;
2146 break;
2147 case OPT_password:
2148 if (opt_arg) {
2149 my_free(options->password);
2150 options->password =
2151 my_strdup(key_memory_mysql_options, opt_arg, MYF(MY_WME));
2152 }
2153 break;
2154 case OPT_pipe:
2155 options->protocol = MYSQL_PROTOCOL_PIPE;
2156 break;
2157 case OPT_connect_timeout:
2158 case OPT_timeout:
2159 if (opt_arg) options->connect_timeout = atoi(opt_arg);
2160 break;
2161 case OPT_user:
2162 if (opt_arg) {
2163 my_free(options->user);
2164 options->user =
2165 my_strdup(key_memory_mysql_options, opt_arg, MYF(MY_WME));
2166 }
2167 break;
2168 case OPT_init_command:
2169 add_init_command(options, opt_arg);
2170 break;
2171 case OPT_host:
2172 if (opt_arg) {
2173 my_free(options->host);
2174 options->host =
2175 my_strdup(key_memory_mysql_options, opt_arg, MYF(MY_WME));
2176 }
2177 break;
2178 case OPT_database:
2179 if (opt_arg) {
2180 my_free(options->db);
2181 options->db =
2182 my_strdup(key_memory_mysql_options, opt_arg, MYF(MY_WME));
2183 }
2184 break;
2185 case OPT_debug:
2186 #ifndef MYSQL_SERVER
2187 mysql_debug(opt_arg ? opt_arg : "d:t:o,/tmp/client.trace");
2188 break;
2189 #endif
2190 case OPT_return_found_rows:
2191 options->client_flag |= CLIENT_FOUND_ROWS;
2192 break;
2193 case OPT_ssl_key:
2194 my_free(options->ssl_key);
2195 options->ssl_key =
2196 my_strdup(key_memory_mysql_options, opt_arg, MYF(MY_WME));
2197 break;
2198 case OPT_ssl_cert:
2199 my_free(options->ssl_cert);
2200 options->ssl_cert =
2201 my_strdup(key_memory_mysql_options, opt_arg, MYF(MY_WME));
2202 break;
2203 case OPT_ssl_ca:
2204 my_free(options->ssl_ca);
2205 options->ssl_ca =
2206 my_strdup(key_memory_mysql_options, opt_arg, MYF(MY_WME));
2207 break;
2208 case OPT_ssl_capath:
2209 my_free(options->ssl_capath);
2210 options->ssl_capath =
2211 my_strdup(key_memory_mysql_options, opt_arg, MYF(MY_WME));
2212 break;
2213 case OPT_ssl_cipher:
2214 my_free(options->ssl_cipher);
2215 options->ssl_cipher =
2216 my_strdup(key_memory_mysql_options, opt_arg, MYF(MY_WME));
2217 break;
2218 case OPT_tls_ciphersuites:
2219 EXTENSION_SET_STRING(options, tls_ciphersuites, opt_arg);
2220 break;
2221 case OPT_tls_version:
2222 EXTENSION_SET_SSL_STRING(options, tls_version, opt_arg,
2223 SSL_MODE_PREFERRED);
2224 break;
2225 case OPT_ssl_crl:
2226 EXTENSION_SET_SSL_STRING(options, ssl_crl, opt_arg,
2227 SSL_MODE_PREFERRED);
2228 break;
2229 case OPT_ssl_crlpath:
2230 EXTENSION_SET_SSL_STRING(options, ssl_crlpath, opt_arg,
2231 SSL_MODE_PREFERRED);
2232 break;
2233 case OPT_character_sets_dir:
2234 my_free(options->charset_dir);
2235 options->charset_dir =
2236 my_strdup(key_memory_mysql_options, opt_arg, MYF(MY_WME));
2237 break;
2238 case OPT_default_character_set:
2239 my_free(options->charset_name);
2240 options->charset_name =
2241 my_strdup(key_memory_mysql_options, opt_arg, MYF(MY_WME));
2242 break;
2243 case OPT_interactive_timeout:
2244 options->client_flag |= CLIENT_INTERACTIVE;
2245 break;
2246 case OPT_local_infile:
2247 if (!opt_arg || atoi(opt_arg) != 0)
2248 options->client_flag |= CLIENT_LOCAL_FILES;
2249 else
2250 options->client_flag &= ~CLIENT_LOCAL_FILES;
2251 break;
2252 case OPT_disable_local_infile:
2253 options->client_flag &= ~CLIENT_LOCAL_FILES;
2254 break;
2255 case OPT_max_allowed_packet:
2256 if (opt_arg) options->max_allowed_packet = atoi(opt_arg);
2257 break;
2258 case OPT_protocol:
2259 if ((options->protocol = find_type(opt_arg, &sql_protocol_typelib,
2260 FIND_TYPE_BASIC)) <= 0) {
2261 my_message_local(ERROR_LEVEL, EE_UNKNOWN_PROTOCOL_OPTION,
2262 opt_arg);
2263 exit(1);
2264 }
2265 break;
2266 case OPT_shared_memory_base_name:
2267 #if defined(_WIN32)
2268 my_free(options->shared_memory_base_name);
2269
2270 options->shared_memory_base_name =
2271 my_strdup(key_memory_mysql_options, opt_arg, MYF(MY_WME));
2272 #endif
2273 break;
2274 case OPT_multi_results:
2275 options->client_flag |= CLIENT_MULTI_RESULTS;
2276 break;
2277 case OPT_multi_statements:
2278 case OPT_multi_queries:
2279 options->client_flag |=
2280 CLIENT_MULTI_STATEMENTS | CLIENT_MULTI_RESULTS;
2281 break;
2282 case OPT_report_data_truncation:
2283 options->report_data_truncation =
2284 opt_arg ? (atoi(opt_arg) != 0) : true;
2285 break;
2286 case OPT_plugin_dir: {
2287 char buff[FN_REFLEN], buff2[FN_REFLEN];
2288 if (strlen(opt_arg) >= FN_REFLEN) opt_arg[FN_REFLEN] = '\0';
2289 if (my_realpath(buff, opt_arg, 0)) {
2290 DBUG_PRINT("warning",
2291 ("failed to normalize the plugin path: %s", opt_arg));
2292 break;
2293 }
2294 convert_dirname(buff2, buff, nullptr);
2295 EXTENSION_SET_STRING(options, plugin_dir, buff2);
2296 } break;
2297 case OPT_default_auth:
2298 EXTENSION_SET_STRING(options, default_auth, opt_arg);
2299 break;
2300 case OPT_bind_address:
2301 my_free(options->bind_address);
2302 options->bind_address =
2303 my_strdup(key_memory_mysql_options, opt_arg, MYF(MY_WME));
2304 break;
2305 case OPT_enable_cleartext_plugin:
2306 ENSURE_EXTENSIONS_PRESENT(options);
2307 options->extension->enable_cleartext_plugin =
2308 (!opt_arg || atoi(opt_arg) != 0) ? true : false;
2309 break;
2310 case OPT_optional_resultset_metadata:
2311 if (!opt_arg || atoi(opt_arg) != 0)
2312 options->client_flag |= CLIENT_OPTIONAL_RESULTSET_METADATA;
2313 else
2314 options->client_flag &= ~CLIENT_OPTIONAL_RESULTSET_METADATA;
2315 break;
2316
2317 default:
2318 DBUG_PRINT("warning", ("unknown option: %s", option[0]));
2319 }
2320 }
2321 }
2322 }
2323 }
2324
2325 /**************************************************************************
2326 Get column lengths of the current row
2327 If one uses mysql_use_result, res->lengths contains the length information,
2328 else the lengths are calculated from the offset between pointers.
2329 **************************************************************************/
2330
2331 105776959 static void cli_fetch_lengths(ulong *to, MYSQL_ROW column,
2332 unsigned int field_count) {
2333 ulong *prev_length;
2334 105776959 char *start = nullptr;
2335 MYSQL_ROW end;
2336
2337 105776959 prev_length = nullptr; /* Keep gcc happy */
2338
2/2
✓ Branch 0 taken 691916871 times.
✓ Branch 1 taken 105776959 times.
797693830 for (end = column + field_count + 1; column != end; column++, to++) {
2339
2/2
✓ Branch 0 taken 48015058 times.
✓ Branch 1 taken 643901813 times.
691916871 if (!*column) {
2340 48015058 *to = 0; /* Null */
2341 48015058 continue;
2342 }
2343
2/2
✓ Branch 0 taken 538124888 times.
✓ Branch 1 taken 105776925 times.
643901813 if (start) /* Found end of prev string */
2344 538124888 *prev_length = (ulong)(*column - start - 1);
2345 643901813 start = *column;
2346 643901813 prev_length = to;
2347 }
2348 105776959 }
2349
2350 /**
2351 Read field metadata from field descriptor and store it in MYSQL_FIELD
2352 structure. String values in MYSQL_FIELD are allocated in a given allocator
2353 root.
2354
2355 @param mysql connection handle
2356 @param alloc memory allocator root
2357 @param default_value flag telling if default values should be read from
2358 descriptor
2359 @param server_capabilities protocol capability flags which determine format
2360 of the descriptor
2361 @param row field descriptor
2362 @param field address of MYSQL_FIELD structure to store metadata in.
2363
2364 @returns 0 on success.
2365 */
2366
2367 30740011 static int unpack_field(MYSQL *mysql, MEM_ROOT *alloc, bool default_value,
2368 uint server_capabilities, MYSQL_ROWS *row,
2369 MYSQL_FIELD *field) {
2370 ulong lengths[9]; /* Max length of each field */
2371
1/2
✓ Branch 0 taken 30740110 times.
✗ Branch 1 not taken.
30740011 DBUG_TRACE;
2372
2373
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30740110 times.
30740110 if (!field) {
2374 set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
2375 return 1;
2376 }
2377
2378 30740110 memset(field, 0, sizeof(MYSQL_FIELD));
2379
2380
2/2
✓ Branch 0 taken 30740106 times.
✓ Branch 1 taken 4 times.
30740110 if (server_capabilities & CLIENT_PROTOCOL_41) {
2381 uchar *pos;
2382 /* fields count may be wrong */
2383
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 30740052 times.
30740106 cli_fetch_lengths(&lengths[0], row->data, default_value ? 8 : 7);
2384
1/2
✓ Branch 0 taken 30740092 times.
✗ Branch 1 not taken.
30740097 field->catalog = strmake_root(alloc, (char *)row->data[0], lengths[0]);
2385
1/2
✓ Branch 0 taken 30740108 times.
✗ Branch 1 not taken.
30740092 field->db = strmake_root(alloc, (char *)row->data[1], lengths[1]);
2386
1/2
✓ Branch 0 taken 30740109 times.
✗ Branch 1 not taken.
30740108 field->table = strmake_root(alloc, (char *)row->data[2], lengths[2]);
2387
1/2
✓ Branch 0 taken 30740116 times.
✗ Branch 1 not taken.
30740109 field->org_table = strmake_root(alloc, (char *)row->data[3], lengths[3]);
2388
1/2
✓ Branch 0 taken 30740101 times.
✗ Branch 1 not taken.
30740116 field->name = strmake_root(alloc, (char *)row->data[4], lengths[4]);
2389
1/2
✓ Branch 0 taken 30740117 times.
✗ Branch 1 not taken.
30740101 field->org_name = strmake_root(alloc, (char *)row->data[5], lengths[5]);
2390
2391 30740117 field->catalog_length = lengths[0];
2392 30740117 field->db_length = lengths[1];
2393 30740117 field->table_length = lengths[2];
2394 30740117 field->org_table_length = lengths[3];
2395 30740117 field->name_length = lengths[4];
2396 30740117 field->org_name_length = lengths[5];
2397
2398 /* Unpack fixed length parts */
2399
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30740117 times.
30740117 if (lengths[6] != 12) {
2400 /* malformed packet. signal an error. */
2401 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
2402 return 1;
2403 }
2404
2405 30740117 pos = (uchar *)row->data[6];
2406 30740117 field->charsetnr = uint2korr(pos);
2407 30740075 field->length = (uint)uint4korr(pos + 2);
2408 30740096 field->type = (enum enum_field_types)pos[6];
2409 30740096 field->flags = uint2korr(pos + 7);
2410 30740051 field->decimals = (uint)pos[9];
2411
2412
8/8
✓ Branch 0 taken 8248197 times.
✓ Branch 1 taken 22491854 times.
✓ Branch 2 taken 82383 times.
✓ Branch 3 taken 8165814 times.
✓ Branch 4 taken 22570338 times.
✓ Branch 5 taken 3899 times.
✓ Branch 6 taken 63333 times.
✓ Branch 7 taken 22507005 times.
30740051 if (IS_NUM(field->type)) field->flags |= NUM_FLAG;
2413
4/4
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 30739997 times.
✓ Branch 2 taken 20 times.
✓ Branch 3 taken 34 times.
30740051 if (default_value && row->data[7]) {
2414
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 field->def = strmake_root(alloc, (char *)row->data[7], lengths[7]);
2415 20 field->def_length = lengths[7];
2416 } else
2417 30740031 field->def = nullptr;
2418 30740051 field->max_length = 0;
2419 }
2420 #ifndef DELETE_SUPPORT_OF_4_0_PROTOCOL
2421 else {
2422 /*
2423 If any of the row->data[] below is NULL, it can result in a
2424 crash. Error out early as it indicates a malformed packet.
2425 For data[0], data[1] and data[5], strmake_root() will handle
2426 NULL values.
2427 */
2428
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
4 if (!row->data[2] || !row->data[3] || !row->data[4]) {
2429
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
4 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
2430 return 1;
2431 }
2432
2433 cli_fetch_lengths(&lengths[0], row->data, default_value ? 6 : 5);
2434 field->org_table = field->table =
2435 strmake_root(alloc, (char *)row->data[0], lengths[0]);
2436 field->name = strmake_root(alloc, (char *)row->data[1], lengths[1]);
2437 field->length = (uint)uint3korr((uchar *)row->data[2]);
2438 field->type = (enum enum_field_types)(uchar)row->data[3][0];
2439
2440 field->catalog = const_cast<char *>("");
2441 field->db = const_cast<char *>("");
2442 field->catalog_length = 0;
2443 field->db_length = 0;
2444 field->org_table_length = field->table_length = lengths[0];
2445 field->name_length = lengths[1];
2446
2447 if (server_capabilities & CLIENT_LONG_FLAG) {
2448 if (lengths[4] != 3) {
2449 /* malformed packet. signal an error. */
2450 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
2451 return 1;
2452 }
2453 field->flags = uint2korr((uchar *)row->data[4]);
2454 field->decimals = (uint)(uchar)row->data[4][2];
2455 } else {
2456 if (lengths[4] != 2) {
2457 /* malformed packet. signal an error. */
2458 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
2459 return 1;
2460 }
2461 field->flags = (uint)(uchar)row->data[4][0];
2462 field->decimals = (uint)(uchar)row->data[4][1];
2463 }
2464 if (IS_NUM(field->type)) field->flags |= NUM_FLAG;
2465 if (default_value && row->data[5]) {
2466 field->def = strmake_root(alloc, (char *)row->data[5], lengths[5]);
2467 field->def_length = lengths[5];
2468 } else
2469 field->def = nullptr;
2470 field->max_length = 0;
2471 }
2472 #endif /* DELETE_SUPPORT_OF_4_0_PROTOCOL */
2473 30740051 return 0;
2474 30740051 }
2475
2476 /***************************************************************************
2477 Change field rows to field structs
2478 ***************************************************************************/
2479
2480 28 MYSQL_FIELD *unpack_fields(MYSQL *mysql, MYSQL_ROWS *data, MEM_ROOT *alloc,
2481 uint fields, bool default_value,
2482 uint server_capabilities) {
2483 MYSQL_ROWS *row;
2484 MYSQL_FIELD *field, *result;
2485
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 DBUG_TRACE;
2486
2487
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 field = result = (MYSQL_FIELD *)alloc->Alloc((uint)sizeof(*field) * fields);
2488
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 if (!result) {
2489 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
2490 return nullptr;
2491 }
2492 28 memset(field, 0, sizeof(MYSQL_FIELD) * fields);
2493
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 28 times.
82 for (row = data; row; row = row->next, field++) {
2494 /* fields count may be wrong */
2495
2/4
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 54 times.
54 if (field < result || static_cast<uint>(field - result) >= fields) {
2496 return nullptr;
2497 }
2498
2/4
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 54 times.
54 if (unpack_field(mysql, alloc, default_value, server_capabilities, row,
2499 field)) {
2500 return nullptr;
2501 }
2502 }
2503 28 return result;
2504 28 }
2505
2506 /**
2507 Read metadata resultset from server in asynchronous way.
2508
2509 @param[in] mysql connection handle
2510 @param[in] alloc memory allocator root
2511 @param[in] field_count total number of fields
2512 @param[in] field number of columns in single field descriptor
2513 @param[out] ret an array of field rows
2514
2515 @retval NET_ASYNC_NOT_READY metadata resultset not read completely
2516 @retval NET_ASYNC_COMPLETE finished reading metadata resultset
2517 */
2518 122 net_async_status cli_read_metadata_ex_nonblocking(MYSQL *mysql, MEM_ROOT *alloc,
2519 ulong field_count,
2520 unsigned int field,
2521 MYSQL_FIELD **ret) {
2522
1/2
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
122 DBUG_TRACE;
2523 uchar *pos;
2524 ulong pkt_len;
2525 122 NET *net = &mysql->net;
2526
2/6
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 122 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
122 MYSQL_ASYNC *async_data = ASYNC_DATA(mysql);
2527 122 *ret = nullptr;
2528
2529
1/2
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
122 if (!async_data->async_read_metadata_field_len) {
2530 122 async_data->async_read_metadata_field_len =
2531
1/2
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
122 (ulong *)alloc->Alloc(sizeof(ulong) * field);
2532 }
2533
1/2
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
122 if (!async_data->async_read_metadata_fields) {
2534 122 async_data->async_read_metadata_fields =
2535
1/2
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
122 (MYSQL_FIELD *)alloc->Alloc((uint)sizeof(MYSQL_FIELD) * field_count);
2536
1/2
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
122 if (async_data->async_read_metadata_fields)
2537 122 memset(async_data->async_read_metadata_fields, 0,
2538 sizeof(MYSQL_FIELD) * field_count);
2539 }
2540
2541
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 122 times.
122 if (!async_data->async_read_metadata_fields) {
2542 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
2543 goto end;
2544 }
2545
2546
1/2
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
122 if (!async_data->async_read_metadata_data.data) {
2547 122 async_data->async_read_metadata_data.data =
2548
1/2
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
122 (MYSQL_ROW)alloc->Alloc(sizeof(char *) * (field + 1));
2549 122 memset(async_data->async_read_metadata_data.data, 0,
2550 122 sizeof(char *) * (field + 1));
2551 }
2552
2553 /*
2554 In this below loop we read each column info as 1 single row
2555 and save it in mysql->fields array
2556 */
2557
2/2
✓ Branch 0 taken 135 times.
✓ Branch 1 taken 122 times.
257 while (async_data->async_read_metadata_cur_field < field_count) {
2558 int res;
2559
1/2
✓ Branch 0 taken 135 times.
✗ Branch 1 not taken.
135 if (read_one_row_nonblocking(mysql, field,
2560 async_data->async_read_metadata_data.data,
2561 async_data->async_read_metadata_field_len,
2562
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 135 times.
135 &res) == NET_ASYNC_NOT_READY) {
2563 return NET_ASYNC_NOT_READY;
2564 }
2565
2566
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 135 times.
135 if (res == -1) {
2567 goto end;
2568 }
2569
2570
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 135 times.
135 if (unpack_field(mysql, alloc, false, mysql->server_capabilities,
2571 &async_data->async_read_metadata_data,
2572 135 async_data->async_read_metadata_fields +
2573
1/2
✓ Branch 0 taken 135 times.
✗ Branch 1 not taken.
135 async_data->async_read_metadata_cur_field)) {
2574 goto end;
2575 }
2576 135 async_data->async_read_metadata_cur_field++;
2577 }
2578
2579 /* Read EOF packet in case of old client */
2580
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 122 times.
122 if (!(mysql->server_capabilities & CLIENT_DEPRECATE_EOF)) {
2581 if (cli_safe_read_nonblocking(mysql, nullptr, &pkt_len) ==
2582 NET_ASYNC_NOT_READY) {
2583 return NET_ASYNC_NOT_READY;
2584 }
2585
2586 if (pkt_len == packet_error) {
2587 goto end;
2588 }
2589
2590 pos = net->read_pos;
2591 if (*pos == 254) {
2592 mysql->warning_count = uint2korr(pos + 1);
2593 mysql->server_status = uint2korr(pos + 3);
2594 }
2595 }
2596 122 *ret = async_data->async_read_metadata_fields;
2597
2598 122 end:
2599 122 async_data->async_read_metadata_field_len = nullptr;
2600 122 async_data->async_read_metadata_fields = nullptr;
2601 122 memset(&async_data->async_read_metadata_data, 0,
2602 sizeof(async_data->async_read_metadata_data));
2603 122 async_data->async_read_metadata_cur_field = 0;
2604 122 return NET_ASYNC_COMPLETE;
2605 122 }
2606
2607 /**
2608 Read metadata resultset from server
2609 Memory allocated in a given allocator root.
2610
2611 @param[in] mysql connection handle
2612 @param[in] alloc memory allocator root
2613 @param[in] field_count total number of fields
2614 @param[in] field number of columns in single field descriptor
2615
2616 @retval an array of field rows
2617
2618 */
2619 10463087 MYSQL_FIELD *cli_read_metadata_ex(MYSQL *mysql, MEM_ROOT *alloc,
2620 ulong field_count, unsigned int field) {
2621 ulong *len;
2622 uint f;
2623 uchar *pos;
2624 MYSQL_FIELD *fields, *result;
2625 MYSQL_ROWS data;
2626 10463087 NET *net = &mysql->net;
2627 size_t size;
2628
2629
1/2
✓ Branch 0 taken 10463207 times.
✗ Branch 1 not taken.
10463087 DBUG_TRACE;
2630
2631
1/2
✓ Branch 0 taken 10463206 times.
✗ Branch 1 not taken.
10463207 len = (ulong *)alloc->Alloc(sizeof(ulong) * field);
2632
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10463206 times.
10463206 if (!len) {
2633 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
2634 end_server(mysql);
2635 return nullptr;
2636 }
2637 10463206 size = sizeof(MYSQL_FIELD) * field_count;
2638
2639
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10463206 times.
10463206 if (field_count != (size / sizeof(MYSQL_FIELD))) {
2640 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
2641 end_server(mysql);
2642 return nullptr;
2643 }
2644
2645
1/2
✓ Branch 0 taken 10463203 times.
✗ Branch 1 not taken.
10463206 fields = result = (MYSQL_FIELD *)alloc->Alloc(size);
2646
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10463203 times.
10463203 if (!result) {
2647 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
2648 end_server(mysql);
2649 return nullptr;
2650 }
2651 10463203 memset(fields, 0, sizeof(MYSQL_FIELD) * field_count);
2652
2653
1/2
✓ Branch 0 taken 10463200 times.
✗ Branch 1 not taken.
10463203 data.data = (MYSQL_ROW)alloc->Alloc(sizeof(char *) * (field + 1));
2654 10463200 memset(data.data, 0, sizeof(char *) * (field + 1));
2655
2656 /*
2657 In this below loop we read each column info as 1 single row
2658 and save it in mysql->fields array
2659 */
2660
2/2
✓ Branch 0 taken 30739869 times.
✓ Branch 1 taken 10463215 times.
41203084 for (f = 0; f < field_count; ++f) {
2661
2/4
✓ Branch 0 taken 30739925 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 30739925 times.
30739869 if (read_one_row(mysql, field, data.data, len) == -1) return nullptr;
2662
2/4
✓ Branch 0 taken 30739884 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 30739884 times.
30739925 if (unpack_field(mysql, alloc, false, mysql->server_capabilities, &data,
2663 fields++))
2664 return nullptr;
2665 }
2666 /* Read EOF packet in case of old client */
2667
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10463215 times.
10463215 if (!(mysql->server_capabilities & CLIENT_DEPRECATE_EOF)) {
2668 if (packet_error == cli_safe_read(mysql, nullptr)) return nullptr;
2669 pos = net->read_pos;
2670 if (*pos == 254) {
2671 mysql->warning_count = uint2korr(pos + 1);
2672 mysql->server_status = uint2korr(pos + 3);
2673 }
2674 }
2675 10463206 return result;
2676 10463206 }
2677
2678 10461477 static int alloc_field_alloc(MYSQL *mysql) {
2679
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 10461465 times.
10461477 if (mysql->field_alloc == nullptr) {
2680 11 mysql->field_alloc =
2681 12 new (my_malloc(key_memory_MYSQL, sizeof(MEM_ROOT), MYF(MY_WME)))
2682 12 MEM_ROOT(PSI_NOT_INSTRUMENTED, 8192); /* Assume rowlength < 8192 */
2683
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (mysql->field_alloc == nullptr) {
2684 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
2685 return 1;
2686 }
2687 }
2688 /* At this point the NET is receiving a resultset. max packet should be set */
2689
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10461476 times.
10461476 assert(mysql->net.max_packet_size != 0);
2690 /* Limit the size of the columns buffer to MAX packet size or 1M */
2691 10461501 mysql->field_alloc->set_max_capacity(
2692 10461476 std::max(1024UL * 1024UL, mysql->net.max_packet_size));
2693 10461446 return 0;
2694 }
2695
2696 /**
2697 Read metadata resultset from server
2698
2699 @param[in] mysql connection handle
2700 @param[in] field_count total number of fields
2701 @param[in] field number of columns in single field descriptor
2702
2703 @retval an array of field rows
2704
2705 */
2706 10461339 MYSQL_FIELD *cli_read_metadata(MYSQL *mysql, ulong field_count,
2707 unsigned int field) {
2708 10461339 alloc_field_alloc(mysql);
2709 10461328 return cli_read_metadata_ex(mysql, mysql->field_alloc, field_count, field);
2710 }
2711
2712 /**
2713 Helper method to read metadata in asynchronous way.
2714 */
2715 122 static net_async_status cli_read_metadata_nonblocking(MYSQL *mysql,
2716 ulong field_count,
2717 unsigned int field,
2718 MYSQL_FIELD **ret) {
2719 122 alloc_field_alloc(mysql);
2720 122 if (cli_read_metadata_ex_nonblocking(mysql, mysql->field_alloc, field_count,
2721
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 122 times.
122 field, ret) == NET_ASYNC_NOT_READY) {
2722 return NET_ASYNC_NOT_READY;
2723 }
2724 122 return NET_ASYNC_COMPLETE;
2725 }
2726
2727 /**
2728 Read resultset metadata returned by COM_QUERY command.
2729
2730 @param[in] mysql Client connection handle.
2731 @param[in] pos Position in the packet where the metadata
2732 starts.
2733 @param[in] field_count Number of columns in the field descriptor.
2734
2735 @retval 0 Success.
2736 @retval 1 Error.
2737 */
2738 10458961 static int read_com_query_metadata(MYSQL *mysql, uchar *pos,
2739 ulong field_count) {
2740 /* Store resultset metadata flag. */
2741
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 10458930 times.
10458961 if (mysql->client_flag & CLIENT_OPTIONAL_RESULTSET_METADATA) {
2742 31 mysql->resultset_metadata = static_cast<enum enum_resultset_metadata>(*pos);
2743 } else {
2744 10458930 mysql->resultset_metadata = RESULTSET_METADATA_FULL;
2745 }
2746
2747
2/3
✓ Branch 0 taken 10458982 times.
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
10458961 switch (mysql->resultset_metadata) {
2748 10458982 case RESULTSET_METADATA_FULL:
2749 /* Read metadata. */
2750
3/6
✓ Branch 0 taken 10419574 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10419574 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
10419578 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_FIELD_DEF);
2751
2752
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10459066 times.
10458978 if (!(mysql->fields = cli_read_metadata(mysql, field_count,
2753
1/2
✓ Branch 0 taken 10459014 times.
✗ Branch 1 not taken.
10458978 protocol_41(mysql) ? 7 : 5))) {
2754 3 mysql->field_alloc->Clear();
2755 return 1;
2756 }
2757 10459066 break;
2758
2759 16 case RESULTSET_METADATA_NONE:
2760 /* Skip metadata. */
2761 16 mysql->fields = nullptr;
2762 16 break;
2763
2764 default:
2765 /* Unknown metadata flag. */
2766 mysql->fields = nullptr;
2767 return 1;
2768 }
2769
2770 10459082 return 0;
2771 }
2772
2773 /**
2774 Read resultset metadata returned by COM_QUERY command in asynchronous way.
2775
2776 @param[in] mysql Client connection handle.
2777 @param[in] pos Position in the packet where the metadata
2778 starts.
2779 @param[in] field_count Number of columns in the field descriptor.
2780 @param[out] res set to false in case of success and true for
2781 error.
2782
2783 @retval NET_ASYNC_NOT_READY metadata resultset not read completely
2784 @retval NET_ASYNC_COMPLETE finished reading metadata resultset
2785 */
2786 122 static net_async_status read_com_query_metadata_nonblocking(MYSQL *mysql,
2787 uchar *pos,
2788 ulong field_count,
2789 int *res) {
2790
1/2
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
122 DBUG_TRACE;
2791 /* pos is only set on the first reentrant call. */
2792
1/2
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
122 if (pos) {
2793 /* Store resultset metadata flag. */
2794
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 122 times.
122 if (mysql->client_flag & CLIENT_OPTIONAL_RESULTSET_METADATA) {
2795 mysql->resultset_metadata =
2796 static_cast<enum enum_resultset_metadata>(*pos);
2797 } else {
2798 122 mysql->resultset_metadata = RESULTSET_METADATA_FULL;
2799 }
2800 }
2801
2802
1/3
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
122 switch (mysql->resultset_metadata) {
2803 122 case RESULTSET_METADATA_FULL:
2804 /* Read metadata. */
2805
2/10
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 122 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
122 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_FIELD_DEF);
2806
2807
1/2
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
122 if (cli_read_metadata_nonblocking(
2808
2/4
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 122 times.
244 mysql, field_count, protocol_41(mysql) ? 7 : 5, &mysql->fields) ==
2809 NET_ASYNC_NOT_READY) {
2810 return NET_ASYNC_NOT_READY;
2811 }
2812
2813
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 122 times.
122 if (!mysql->fields) {
2814 mysql->field_alloc->Clear();
2815 *res = 1;
2816 return NET_ASYNC_COMPLETE;
2817 }
2818 122 break;
2819
2820 case RESULTSET_METADATA_NONE:
2821 /* Skip metadata. */
2822 mysql->fields = nullptr;
2823 break;
2824
2825 default:
2826 /* Unknown metadata flag. */
2827 mysql->fields = nullptr;
2828 *res = 1;
2829 return NET_ASYNC_COMPLETE;
2830 }
2831
2832 122 *res = 0;
2833 122 return NET_ASYNC_COMPLETE;
2834 122 }
2835
2836 171032 net_async_status cli_read_rows_nonblocking(MYSQL *mysql,
2837 MYSQL_FIELD *mysql_fields,
2838 unsigned int fields,
2839 MYSQL_DATA **result_out) {
2840 uint field;
2841 ulong pkt_len;
2842 ulong len;
2843 uchar *cp;
2844 char *to, *end_to;
2845 MYSQL_ROWS *cur;
2846 171032 NET *net = &mysql->net;
2847 bool is_data_packet;
2848
1/2
✓ Branch 0 taken 171032 times.
✗ Branch 1 not taken.
171032 DBUG_TRACE;
2849
2/6
✓ Branch 0 taken 171032 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 171032 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
171032 MYSQL_ASYNC *async_context = ASYNC_DATA(mysql);
2850
1/2
✓ Branch 0 taken 171032 times.
✗ Branch 1 not taken.
171032 NET_ASYNC *net_async = NET_ASYNC_DATA(net);
2851 171032 *result_out = nullptr;
2852
2853
3/4
✓ Branch 0 taken 171032 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 170901 times.
✓ Branch 3 taken 131 times.
171032 if (cli_safe_read_nonblocking(mysql, &is_data_packet, &pkt_len) ==
2854 NET_ASYNC_NOT_READY) {
2855 170901 return NET_ASYNC_NOT_READY;
2856 }
2857
2858 131 mysql->packet_length = pkt_len;
2859
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 131 times.
131 if (pkt_len == packet_error) {
2860 if (net_async->read_rows_is_first_read) {
2861 free_rows(async_context->rows_result_buffer);
2862 async_context->rows_result_buffer = nullptr;
2863 }
2864 net_async->read_rows_is_first_read = true;
2865 return NET_ASYNC_COMPLETE;
2866 }
2867
2868
1/2
✓ Branch 0 taken 131 times.
✗ Branch 1 not taken.
131 if (net_async->read_rows_is_first_read) {
2869 MYSQL_DATA *result;
2870 131 if (!(result =
2871
1/2
✓ Branch 0 taken 131 times.
✗ Branch 1 not taken.
131 (MYSQL_DATA *)my_malloc(key_memory_MYSQL_DATA, sizeof(MYSQL_DATA),
2872
2/4
✓ Branch 0 taken 131 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 131 times.
262 MYF(MY_WME | MY_ZEROFILL))) ||
2873 131 !(result->alloc =
2874
2/4
✓ Branch 0 taken 131 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 131 times.
131 (MEM_ROOT *)my_malloc(key_memory_MYSQL_DATA, sizeof(MEM_ROOT),
2875 MYF(MY_WME | MY_ZEROFILL)))) {
2876 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
2877 net_async->read_rows_is_first_read = true;
2878 free_rows(result);
2879 return NET_ASYNC_COMPLETE;
2880 }
2881 131 async_context->rows_result_buffer = result;
2882 131 ::new ((void *)result->alloc)
2883 131 MEM_ROOT(PSI_NOT_INSTRUMENTED, 8192); /* Assume rowlength < 8192 */
2884 131 async_context->prev_row_ptr = &result->data;
2885 131 result->rows = 0;
2886 131 result->fields = fields;
2887
2888 131 net_async->read_rows_is_first_read = false;
2889 }
2890
2891 /*
2892 The last EOF packet is either a single 254 character or (in MySQL 4.1)
2893 254 followed by 1-7 status bytes or an OK packet starting with 0xFE
2894 */
2895
5/6
✓ Branch 0 taken 270 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 139 times.
✓ Branch 3 taken 131 times.
✓ Branch 4 taken 139 times.
✓ Branch 5 taken 131 times.
270 while (*(cp = net->read_pos) == 0 || is_data_packet) {
2896 139 MYSQL_DATA *result = async_context->rows_result_buffer;
2897 139 result->rows++;
2898
3/6
✓ Branch 0 taken 139 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 139 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 139 times.
278 if (!(cur = (MYSQL_ROWS *)result->alloc->Alloc(sizeof(MYSQL_ROWS))) ||
2899
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 139 times.
139 !(cur->data = ((MYSQL_ROW)result->alloc->Alloc(
2900
1/2
✓ Branch 0 taken 139 times.
✗ Branch 1 not taken.
139 (fields + 1) * sizeof(char *) + pkt_len)))) {
2901 free_rows(result);
2902 async_context->rows_result_buffer = nullptr;
2903 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
2904 net_async->read_rows_is_first_read = true;
2905 return NET_ASYNC_COMPLETE;
2906 }
2907 139 *async_context->prev_row_ptr = cur;
2908 139 async_context->prev_row_ptr = &cur->next;
2909 139 to = (char *)(cur->data + fields + 1);
2910 139 end_to = to + pkt_len - 1;
2911
2/2
✓ Branch 0 taken 166 times.
✓ Branch 1 taken 139 times.
305 for (field = 0; field < fields; field++) {
2912
3/4
✓ Branch 0 taken 166 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 157 times.
166 if ((len = (ulong)net_field_length(&cp)) ==
2913 NULL_LENGTH) { /* null field */
2914 9 cur->data[field] = nullptr;
2915 } else {
2916 157 cur->data[field] = to;
2917
2/4
✓ Branch 0 taken 157 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 157 times.
157 if (to > end_to || len > (ulong)(end_to - to)) {
2918 free_rows(result);
2919 async_context->rows_result_buffer = nullptr;
2920 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
2921 net_async->read_rows_is_first_read = true;
2922 return NET_ASYNC_COMPLETE;
2923 }
2924 157 memcpy(to, (char *)cp, len);
2925 157 to[len] = 0;
2926 157 to += len + 1;
2927 157 cp += len;
2928
1/2
✓ Branch 0 taken 157 times.
✗ Branch 1 not taken.
157 if (mysql_fields) {
2929
2/2
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 11 times.
157 if (mysql_fields[field].max_length < len)
2930 146 mysql_fields[field].max_length = len;
2931 }
2932 }
2933 }
2934 139 cur->data[field] = to; /* End of last field */
2935
2/4
✓ Branch 0 taken 139 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 139 times.
139 if (cli_safe_read_nonblocking(mysql, &is_data_packet, &pkt_len) ==
2936 NET_ASYNC_NOT_READY) {
2937 return NET_ASYNC_NOT_READY;
2938 }
2939 139 mysql->packet_length = pkt_len;
2940
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 139 times.
139 if (pkt_len == packet_error) {
2941 free_rows(async_context->rows_result_buffer);
2942 async_context->rows_result_buffer = nullptr;
2943 net_async->read_rows_is_first_read = true;
2944 return NET_ASYNC_COMPLETE;
2945 }
2946 }
2947
2948 131 *async_context->prev_row_ptr = nullptr; /* last pointer is null */
2949 /* read EOF packet or OK packet if it is new client */
2950
1/2
✓ Branch 0 taken 131 times.
✗ Branch 1 not taken.
131 if (pkt_len > 1) {
2951
2/4
✓ Branch 0 taken 131 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 131 times.
✗ Branch 3 not taken.
131 if (mysql->server_capabilities & CLIENT_DEPRECATE_EOF && !is_data_packet)
2952
1/2
✓ Branch 0 taken 131 times.
✗ Branch 1 not taken.
131 read_ok_ex(mysql, pkt_len);
2953 else {
2954 mysql->warning_count = uint2korr(cp + 1);
2955 mysql->server_status = uint2korr(cp + 3);
2956 }
2957
2958
3/8
✓ Branch 0 taken 131 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 131 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 131 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
131 DBUG_PRINT("info", ("status: %u warning_count: %u", mysql->server_status,
2959 mysql->warning_count));
2960 }
2961
2962 #if defined(CLIENT_PROTOCOL_TRACING)
2963
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 119 times.
131 if (mysql->server_status & SERVER_MORE_RESULTS_EXISTS)
2964
2/10
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
12 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_RESULT);
2965 else
2966
2/10
✓ Branch 0 taken 119 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 119 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
119 MYSQL_TRACE_STAGE(mysql, READY_FOR_COMMAND);
2967 #endif
2968
3/8
✓ Branch 0 taken 131 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 131 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 131 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
131 DBUG_PRINT("exit",
2969 ("Got %lu rows", (ulong)async_context->rows_result_buffer->rows));
2970 131 *result_out = async_context->rows_result_buffer;
2971 131 async_context->rows_result_buffer = nullptr;
2972 131 net_async->read_rows_is_first_read = true;
2973 131 return NET_ASYNC_COMPLETE;
2974 171032 }
2975
2976 /* Read all rows (data) from server */
2977
2978 10384392 MYSQL_DATA *cli_read_rows(MYSQL *mysql, MYSQL_FIELD *mysql_fields,
2979 unsigned int fields) {
2980 uint field;
2981 ulong pkt_len;
2982 ulong len;
2983 uchar *cp;
2984 char *to, *end_to;
2985 MYSQL_DATA *result;
2986 MYSQL_ROWS **prev_ptr, *cur;
2987 10384392 NET *net = &mysql->net;
2988 bool is_data_packet;
2989
1/2
✓ Branch 0 taken 10384507 times.
✗ Branch 1 not taken.
10384392 DBUG_TRACE;
2990
2991
3/4
✓ Branch 0 taken 10384508 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4480 times.
✓ Branch 3 taken 10380028 times.
10384507 if ((pkt_len = cli_safe_read(mysql, &is_data_packet)) == packet_error)
2992 4480 return nullptr;
2993
2994
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10380028 times.
10380028 if (pkt_len == 0) return nullptr;
2995 10380034 if (!(result =
2996
1/2
✓ Branch 0 taken 10380029 times.
✗ Branch 1 not taken.
10380028 (MYSQL_DATA *)my_malloc(key_memory_MYSQL_DATA, sizeof(MYSQL_DATA),
2997
3/4
✓ Branch 0 taken 10380027 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10380034 times.
20760061 MYF(MY_WME | MY_ZEROFILL))) ||
2998 10380032 !(result->alloc =
2999
2/4
✓ Branch 0 taken 10380032 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10380032 times.
10380027 (MEM_ROOT *)my_malloc(key_memory_MYSQL_DATA, sizeof(MEM_ROOT),
3000 MYF(MY_WME | MY_ZEROFILL)))) {
3001 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
3002 free_rows(result);
3003 return nullptr;
3004 }
3005 10380034 ::new ((void *)result->alloc)
3006 10380034 MEM_ROOT(PSI_NOT_INSTRUMENTED, 8192); /* Assume rowlength < 8192 */
3007 10379979 prev_ptr = &result->data;
3008 10379979 result->rows = 0;
3009 10379979 result->fields = fields;
3010
3011 /*
3012 The last EOF packet is either a single 254 character or (in MySQL 4.1)
3013 254 followed by 1-7 status bytes or an OK packet starting with 0xFE
3014 */
3015
3016
6/6
✓ Branch 0 taken 112069747 times.
✓ Branch 1 taken 1322215 times.
✓ Branch 2 taken 101689879 times.
✓ Branch 3 taken 10379868 times.
✓ Branch 4 taken 103012108 times.
✓ Branch 5 taken 10379854 times.
113391962 while (*(cp = net->read_pos) == 0 || is_data_packet) {
3017 103012108 ulong packet_left = pkt_len;
3018 103012108 result->rows++;
3019
3/6
✓ Branch 0 taken 103012139 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 103012139 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 103012138 times.
206024246 if (!(cur = (MYSQL_ROWS *)result->alloc->Alloc(sizeof(MYSQL_ROWS))) ||
3020
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 103012136 times.
103012138 !(cur->data = ((MYSQL_ROW)result->alloc->Alloc(
3021
1/2
✓ Branch 0 taken 103012138 times.
✗ Branch 1 not taken.
103012139 (fields + 1) * sizeof(char *) + pkt_len)))) {
3022 free_rows(result);
3023 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
3024 return nullptr;
3025 }
3026 103012138 *prev_ptr = cur;
3027 103012138 prev_ptr = &cur->next;
3028 103012138 to = (char *)(cur->data + fields + 1);
3029 103012138 end_to = to + pkt_len - 1;
3030
2/2
✓ Branch 0 taken 527775889 times.
✓ Branch 1 taken 103012163 times.
630788052 for (field = 0; field < fields; field++) {
3031 527775889 uint length_len = 0;
3032
3/4
✓ Branch 0 taken 527775861 times.
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 527775866 times.
1055551727 if (packet_left < 1 ||
3033
2/4
✓ Branch 0 taken 527775838 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 527775866 times.
527775861 packet_left < (length_len = net_field_length_size(cp))) {
3034 free_rows(result);
3035 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
3036 return nullptr;
3037 }
3038
3/4
✓ Branch 0 taken 527775880 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 60744554 times.
✓ Branch 3 taken 467031326 times.
527775866 if ((len = (ulong)net_field_length(&cp)) ==
3039 NULL_LENGTH) { /* null field */
3040 60744554 cur->data[field] = nullptr;
3041 60744554 packet_left -= length_len;
3042 } else {
3043 467031326 cur->data[field] = to;
3044
2/4
✓ Branch 0 taken 467031350 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 467031350 times.
467031326 DBUG_EXECUTE_IF("simulate_invalid_packet_data", {
3045 to = end_to + 1;
3046 len = ULONG_MAX - 1;
3047 });
3048
2/4
✓ Branch 0 taken 467031357 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 467031360 times.
467031350 if (to > end_to || len > (ulong)(end_to - to)) {
3049 free_rows(result);
3050 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
3051 return nullptr;
3052 }
3053 467031360 memcpy(to, (char *)cp, len);
3054 467031360 to[len] = 0;
3055 467031360 to += len + 1;
3056 467031360 cp += len;
3057 467031360 packet_left -= len + length_len;
3058
2/2
✓ Branch 0 taken 467030883 times.
✓ Branch 1 taken 477 times.
467031360 if (mysql_fields) {
3059
2/2
✓ Branch 0 taken 22365250 times.
✓ Branch 1 taken 444665633 times.
467030883 if (mysql_fields[field].max_length < len)
3060 22365250 mysql_fields[field].max_length = len;
3061 }
3062 }
3063 }
3064 103012163 cur->data[field] = to; /* End of last field */
3065
3/4
✓ Branch 0 taken 103012146 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 163 times.
✓ Branch 3 taken 103011983 times.
103012163 if ((pkt_len = cli_safe_read(mysql, &is_data_packet)) == packet_error) {
3066
1/2
✓ Branch 0 taken 163 times.
✗ Branch 1 not taken.
163 free_rows(result);
3067 163 return nullptr;
3068 }
3069 }
3070 10379854 *prev_ptr = nullptr; /* last pointer is null */
3071 /* read EOF packet or OK packet if it is new client */
3072
1/2
✓ Branch 0 taken 10379860 times.
✗ Branch 1 not taken.
10379854 if (pkt_len > 1) {
3073
3/4
✓ Branch 0 taken 10379863 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10379858 times.
✓ Branch 3 taken 5 times.
10379860 if (mysql->server_capabilities & CLIENT_DEPRECATE_EOF && !is_data_packet)
3074
1/2
✓ Branch 0 taken 10379778 times.
✗ Branch 1 not taken.
10379858 read_ok_ex(mysql, pkt_len);
3075 else {
3076 2 mysql->warning_count = uint2korr(cp + 1);
3077 mysql->server_status = uint2korr(cp + 3);
3078 }
3079
3080
3/8
✓ Branch 0 taken 10379854 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10379841 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10379841 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
10379778 DBUG_PRINT("info", ("status: %u warning_count: %u", mysql->server_status,
3081 mysql->warning_count));
3082 }
3083
3084 #if defined(CLIENT_PROTOCOL_TRACING)
3085
2/2
✓ Branch 0 taken 771430 times.
✓ Branch 1 taken 9568981 times.
10340411 if (mysql->server_status & SERVER_MORE_RESULTS_EXISTS)
3086
2/10
✓ Branch 0 taken 771430 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 771430 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
771430 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_RESULT);
3087 else
3088
3/10
✓ Branch 0 taken 9568976 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9568976 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
9568981 MYSQL_TRACE_STAGE(mysql, READY_FOR_COMMAND);
3089 #endif
3090
3/8
✓ Branch 0 taken 10379747 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10379846 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10379846 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
10379805 DBUG_PRINT("exit", ("Got %lu rows", (ulong)result->rows));
3091 10379844 return result;
3092 10384487 }
3093
3094 31168808 static int read_one_row_complete(MYSQL *mysql, ulong pkt_len,
3095 bool is_data_packet, uint fields,
3096 MYSQL_ROW row, ulong *lengths) {
3097
1/2
✓ Branch 0 taken 31168865 times.
✗ Branch 1 not taken.
31168808 DBUG_TRACE;
3098 uint field;
3099 ulong len;
3100 uchar *pos, *prev_pos, *end_pos;
3101 31168865 NET *net = &mysql->net;
3102
3103
4/4
✓ Branch 0 taken 31168688 times.
✓ Branch 1 taken 177 times.
✓ Branch 2 taken 43993 times.
✓ Branch 3 taken 31124695 times.
31168865 if (net->read_pos[0] != 0x00 && !is_data_packet) {
3104
1/2
✓ Branch 0 taken 43993 times.
✗ Branch 1 not taken.
43993 if (pkt_len > 1) /* MySQL 4.1 protocol */
3105 {
3106
1/2
✓ Branch 0 taken 43993 times.
✗ Branch 1 not taken.
43993 if (mysql->server_capabilities & CLIENT_DEPRECATE_EOF)
3107
1/2
✓ Branch 0 taken 43993 times.
✗ Branch 1 not taken.
43993 read_ok_ex(mysql, pkt_len);
3108 else {
3109 mysql->warning_count = uint2korr(net->read_pos + 1);
3110 mysql->server_status = uint2korr(net->read_pos + 3);
3111 }
3112 }
3113 #if defined(CLIENT_PROTOCOL_TRACING)
3114
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 43987 times.
43993 if (mysql->server_status & SERVER_MORE_RESULTS_EXISTS)
3115
2/10
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
6 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_RESULT);
3116 else
3117
2/10
✓ Branch 0 taken 43987 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 43987 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
43987 MYSQL_TRACE_STAGE(mysql, READY_FOR_COMMAND);
3118 #endif
3119 43993 return 1; /* End of data */
3120 }
3121 31124872 prev_pos = nullptr; /* allowed to write at packet[-1] */
3122 31124872 pos = net->read_pos;
3123 31124872 end_pos = pos + pkt_len;
3124
2/2
✓ Branch 0 taken 216290882 times.
✓ Branch 1 taken 31124960 times.
247415842 for (field = 0; field < fields; field++) {
3125
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 216290882 times.
216290882 if (pos >= end_pos) {
3126 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
3127 return -1;
3128 }
3129
1/2
✓ Branch 0 taken 216291126 times.
✗ Branch 1 not taken.
216290882 len = (ulong)net_field_length_checked(&pos, (ulong)(end_pos - pos));
3130
3131
2/4
✓ Branch 0 taken 216291201 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 216291201 times.
216291126 DBUG_EXECUTE_IF("simulate_bad_field_length_1", { len = 1000000L; });
3132
2/4
✓ Branch 0 taken 216290970 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 216290970 times.
216291201 DBUG_EXECUTE_IF("simulate_bad_field_length_2", { len = pkt_len - 1; });
3133
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 216290970 times.
216290970 if (pos > end_pos) {
3134 set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
3135 return -1;
3136 }
3137
3138
2/2
✓ Branch 0 taken 46627 times.
✓ Branch 1 taken 216244343 times.
216290970 if (len == NULL_LENGTH) {
3139 46627 row[field] = nullptr;
3140 46627 *lengths++ = 0;
3141 } else {
3142 216244343 row[field] = (char *)pos;
3143 216244343 pos += len;
3144 216244343 *lengths++ = len;
3145 }
3146 /*
3147 It's safe to write to prev_pos here because we already check
3148 for a valid pos in the beginning of this loop.
3149 */
3150
2/2
✓ Branch 0 taken 185166269 times.
✓ Branch 1 taken 31124701 times.
216290970 if (prev_pos) *prev_pos = 0; /* Terminate prev field */
3151 216290970 prev_pos = pos;
3152 }
3153 31124960 row[field] = (char *)prev_pos + 1; /* End of last field */
3154
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 31124960 times.
31124960 if (prev_pos < end_pos) *prev_pos = 0; /* Terminate last field */
3155 31124960 return 0;
3156 31168953 }
3157
3158 /*
3159 Read one row. Uses packet buffer as storage for fields.
3160 When next packet is read, the previous field values are destroyed
3161 */
3162
3163 31168603 static int read_one_row(MYSQL *mysql, uint fields, MYSQL_ROW row,
3164 ulong *lengths) {
3165 ulong pkt_len;
3166 bool is_data_packet;
3167
3168
2/4
✓ Branch 0 taken 31168717 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 31168717 times.
31168603 if ((pkt_len = cli_safe_read(mysql, &is_data_packet)) == packet_error)
3169 return -1;
3170
3171
1/2
✓ Branch 0 taken 31168731 times.
✗ Branch 1 not taken.
31168717 return read_one_row_complete(mysql, pkt_len, is_data_packet, fields, row,
3172 31168731 lengths);
3173 }
3174
3175 141 static net_async_status read_one_row_nonblocking(MYSQL *mysql, uint fields,
3176 MYSQL_ROW row, ulong *lengths,
3177 int *res) {
3178
1/2
✓ Branch 0 taken 141 times.
✗ Branch 1 not taken.
141 DBUG_TRACE;
3179 ulong pkt_len;
3180 bool is_data_packet;
3181 net_async_status status;
3182
3183
1/2
✓ Branch 0 taken 141 times.
✗ Branch 1 not taken.
141 status = cli_safe_read_nonblocking(mysql, &is_data_packet, &pkt_len);
3184
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 141 times.
141 if (status == NET_ASYNC_NOT_READY) {
3185 return status;
3186 }
3187
3188 141 mysql->packet_length = pkt_len;
3189
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 141 times.
141 if (pkt_len == packet_error) {
3190 *res = -1;
3191 return NET_ASYNC_COMPLETE;
3192 }
3193
3194
1/2
✓ Branch 0 taken 141 times.
✗ Branch 1 not taken.
141 *res = read_one_row_complete(mysql, pkt_len, is_data_packet, fields, row,
3195 lengths);
3196 141 return NET_ASYNC_COMPLETE;
3197 141 }
3198
3199 /****************************************************************************
3200 Init MySQL structure or allocate one
3201 ****************************************************************************/
3202
3203 2031659 MYSQL *STDCALL mysql_init(MYSQL *mysql) {
3204
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2031770 times.
2031659 if (mysql_server_init(0, nullptr, nullptr)) return nullptr;
3205
2/2
✓ Branch 0 taken 218674 times.
✓ Branch 1 taken 1813096 times.
2031770 if (!mysql) {
3206
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 218503 times.
218674 if (!(mysql = (MYSQL *)my_malloc(key_memory_MYSQL, sizeof(*mysql),
3207 MYF(MY_WME | MY_ZEROFILL)))) {
3208 set_mysql_error(nullptr, CR_OUT_OF_MEMORY, unknown_sqlstate);
3209 return nullptr;
3210 }
3211 218503 mysql->free_me = true;
3212 } else
3213 1813096 memset(mysql, 0, sizeof(*(mysql)));
3214 2031599 mysql->charset = default_client_charset_info;
3215 2031599 mysql->field_alloc = (MEM_ROOT *)my_malloc(
3216 key_memory_MYSQL, sizeof(*mysql->field_alloc), MYF(MY_WME | MY_ZEROFILL));
3217
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2031725 times.
2031725 if (!mysql->field_alloc) {
3218 set_mysql_error(nullptr, CR_OUT_OF_MEMORY, unknown_sqlstate);
3219 if (mysql->free_me) my_free(mysql);
3220 return nullptr;
3221 }
3222 2031725 my_stpcpy(mysql->net.sqlstate, not_error_sqlstate);
3223
3224 /*
3225 Only enable LOAD DATA INFILE by default if configured with option
3226 ENABLED_LOCAL_INFILE
3227 */
3228
3229 #if defined(ENABLED_LOCAL_INFILE) && !defined(MYSQL_SERVER)
3230 2019188 mysql->options.client_flag |= CLIENT_LOCAL_FILES;
3231 #endif
3232
3233 #if defined(_WIN32)
3234 mysql->options.shared_memory_base_name = my_strdup(
3235 key_memory_mysql_options, def_shared_memory_base_name, MYF(MY_WME));
3236 #endif
3237
3238 2031579 mysql->options.report_data_truncation = true; /* default */
3239
3240 /* Initialize extensions. */
3241
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2031736 times.
2031579 if (!(mysql->extension = mysql_extension_init(mysql))) {
3242 set_mysql_error(nullptr, CR_OUT_OF_MEMORY, unknown_sqlstate);
3243 return nullptr;
3244 }
3245
3246 /*
3247 By default we don't reconnect because it could silently corrupt data (after
3248 reconnection you potentially lose table locks, user variables, session
3249 variables (transactions but they are specifically dealt with in
3250 mysql_reconnect()).
3251 This is a change: < 5.0.3 mysql->reconnect was set to 1 by default.
3252 How this change impacts existing apps:
3253 - existing apps which relied on the default will see a behaviour change;
3254 they will have to set reconnect=1 after mysql_real_connect().
3255 - existing apps which explicitly asked for reconnection (the only way they
3256 could do it was by setting mysql.reconnect to 1 after mysql_real_connect())
3257 will not see a behaviour change.
3258 - existing apps which explicitly asked for no reconnection
3259 (mysql.reconnect=0) will not see a behaviour change.
3260 */
3261 2031736 mysql->reconnect = false;
3262 #if !defined(MYSQL_SERVER)
3263
1/2
✓ Branch 0 taken 2019347 times.
✗ Branch 1 not taken.
2019345 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
3264 2019316 mysql->options.extension->ssl_mode = SSL_MODE_PREFERRED;
3265 #endif
3266 /* by default connection_compressed should be OFF */
3267
2/2
✓ Branch 0 taken 12391 times.
✓ Branch 1 taken 2019316 times.
2031707 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
3268 2031707 mysql->options.extension->connection_compressed = false;
3269
3270 2031707 mysql->resultset_metadata = RESULTSET_METADATA_FULL;
3271
3/4
✓ Branch 0 taken 2031707 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2031672 times.
✓ Branch 3 taken 35 times.
2031707 ASYNC_DATA(mysql)->async_op_status = ASYNC_OP_UNSET;
3272 2031672 return mysql;
3273 }
3274
3275 /*
3276 MYSQL::extension handling (see sql_common.h for declaration
3277 of MYSQL_EXTENSION structure).
3278 */
3279
3280 2051410 MYSQL_EXTENSION *mysql_extension_init(MYSQL *mysql [[maybe_unused]]) {
3281 MYSQL_EXTENSION *ext;
3282
1/2
✓ Branch 0 taken 2051640 times.
✗ Branch 1 not taken.
2051410 DBUG_TRACE;
3283
3284
1/2
✓ Branch 0 taken 2051579 times.
✗ Branch 1 not taken.
2051640 ext = static_cast<MYSQL_EXTENSION *>(my_malloc(PSI_NOT_INSTRUMENTED,
3285 sizeof(MYSQL_EXTENSION),
3286 MYF(MY_WME | MY_ZEROFILL)));
3287 2051609 ext->mysql_async_context = static_cast<MYSQL_ASYNC *>(
3288
1/2
✓ Branch 0 taken 2051609 times.
✗ Branch 1 not taken.
2051579 my_malloc(PSI_NOT_INSTRUMENTED, sizeof(struct MYSQL_ASYNC),
3289 MYF(MY_WME | MY_ZEROFILL)));
3290 /* set default value */
3291 2051609 ext->mysql_async_context->async_op_status = ASYNC_OP_UNSET;
3292 #ifdef MYSQL_SERVER
3293 12687 ext->server_extn = nullptr;
3294 #endif
3295
3/8
✓ Branch 0 taken 2051586 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2051578 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2051578 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2051609 DBUG_PRINT("async",
3296 ("set state=%d", ext->mysql_async_context->async_query_state));
3297 2051612 return ext;
3298 2051578 }
3299
3300 31961796 void mysql_extension_bind_free(MYSQL_EXTENSION *ext) {
3301
1/2
✓ Branch 0 taken 31962322 times.
✗ Branch 1 not taken.
31961796 DBUG_TRACE;
3302
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 31962283 times.
31962322 if (ext->bind_info.n_params) {
3303
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 my_free(ext->bind_info.bind);
3304
2/2
✓ Branch 0 taken 43 times.
✓ Branch 1 taken 39 times.
82 for (uint idx = 0; idx < ext->bind_info.n_params; idx++)
3305
1/2
✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
43 my_free(ext->bind_info.names[idx]);
3306
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 my_free(ext->bind_info.names);
3307 }
3308 31962322 memset(&ext->bind_info, 0, sizeof(ext->bind_info));
3309 31962322 }
3310
3311 2051379 void mysql_extension_free(MYSQL_EXTENSION *ext) {
3312
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2051379 times.
2051379 if (!ext) return;
3313
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2051379 times.
2051379 if (ext->trace_data) my_free(ext->trace_data);
3314
1/2
✓ Branch 0 taken 2051412 times.
✗ Branch 1 not taken.
2051379 if (ext->mysql_async_context) {
3315
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 2051401 times.
2051412 if (ext->mysql_async_context->connect_context) {
3316 11 if (ext->mysql_async_context->connect_context
3317
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 4 times.
11 ->scramble_buffer_allocated) {
3318 7 my_free(ext->mysql_async_context->connect_context->scramble_buffer);
3319 7 ext->mysql_async_context->connect_context->scramble_buffer = nullptr;
3320 }
3321
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 10 times.
11 if (ext->mysql_async_context->connect_context->ssl) {
3322 1 SSL_free(ext->mysql_async_context->connect_context->ssl);
3323 1 ext->mysql_async_context->connect_context->ssl = nullptr;
3324 }
3325 11 my_free(ext->mysql_async_context->connect_context);
3326 11 ext->mysql_async_context->connect_context = nullptr;
3327 }
3328
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2051412 times.
2051412 if (ext->mysql_async_context->async_qp_data) {
3329 my_free(ext->mysql_async_context->async_qp_data);
3330 ext->mysql_async_context->async_qp_data = nullptr;
3331 ext->mysql_async_context->async_qp_data_length = 0;
3332 }
3333 2051412 my_free(ext->mysql_async_context);
3334 2051442 ext->mysql_async_context = nullptr;
3335 }
3336 // free state change related resources.
3337 2051409 free_state_change_info(ext);
3338 2051432 mysql_extension_bind_free(ext);
3339 2051466 my_free(ext);
3340 }
3341
3342 /*
3343 Fill in SSL part of MYSQL structure and set 'use_ssl' flag.
3344 NB! Errors are not reported until you do mysql_real_connect.
3345 */
3346
3347 139047 bool STDCALL mysql_ssl_set(MYSQL *mysql [[maybe_unused]],
3348 const char *key [[maybe_unused]],
3349 const char *cert [[maybe_unused]],
3350 const char *ca [[maybe_unused]],
3351 const char *capath [[maybe_unused]],
3352 const char *cipher [[maybe_unused]]) {
3353 139047 bool result = false;
3354
1/2
✓ Branch 0 taken 139047 times.
✗ Branch 1 not taken.
139047 DBUG_TRACE;
3355
1/2
✓ Branch 0 taken 139047 times.
✗ Branch 1 not taken.
139047 result = mysql_options(mysql, MYSQL_OPT_SSL_KEY, key) +
3356
1/2
✓ Branch 0 taken 139047 times.
✗ Branch 1 not taken.
139047 mysql_options(mysql, MYSQL_OPT_SSL_CERT, cert) +
3357
1/2
✓ Branch 0 taken 139047 times.
✗ Branch 1 not taken.
139047 mysql_options(mysql, MYSQL_OPT_SSL_CA, ca) +
3358
1/2
✓ Branch 0 taken 139046 times.
✗ Branch 1 not taken.
139047 mysql_options(mysql, MYSQL_OPT_SSL_CAPATH, capath) +
3359
1/2
✓ Branch 0 taken 139047 times.
✗ Branch 1 not taken.
139046 mysql_options(mysql, MYSQL_OPT_SSL_CIPHER, cipher)
3360 ? true
3361 : false;
3362 139047 return result;
3363 139047 }
3364
3365 /*
3366 Free strings in the SSL structure and clear 'use_ssl' flag.
3367 NB! Errors are not reported until you do mysql_real_connect.
3368 */
3369
3370 2078184 static void mysql_ssl_free(MYSQL *mysql) {
3371
1/2
✓ Branch 0 taken 2078364 times.
✗ Branch 1 not taken.
2078184 DBUG_TRACE;
3372
3373
1/2
✓ Branch 0 taken 2078359 times.
✗ Branch 1 not taken.
2078364 my_free(mysql->options.ssl_key);
3374
1/2
✓ Branch 0 taken 2078353 times.
✗ Branch 1 not taken.
2078359 my_free(mysql->options.ssl_cert);
3375
1/2
✓ Branch 0 taken 2078353 times.
✗ Branch 1 not taken.
2078353 my_free(mysql->options.ssl_ca);
3376
1/2
✓ Branch 0 taken 2078355 times.
✗ Branch 1 not taken.
2078353 my_free(mysql->options.ssl_capath);
3377
1/2
✓ Branch 0 taken 2078292 times.
✗ Branch 1 not taken.
2078355 my_free(mysql->options.ssl_cipher);
3378
2/2
✓ Branch 0 taken 2031547 times.
✓ Branch 1 taken 46745 times.
2078292 if (mysql->options.extension) {
3379
1/2
✓ Branch 0 taken 2031560 times.
✗ Branch 1 not taken.
2031547 my_free(mysql->options.extension->tls_version);
3380
1/2
✓ Branch 0 taken 2031570 times.
✗ Branch 1 not taken.
2031560 my_free(mysql->options.extension->ssl_crl);
3381
1/2
✓ Branch 0 taken 2031572 times.
✗ Branch 1 not taken.
2031570 my_free(mysql->options.extension->ssl_crlpath);
3382
1/2
✓ Branch 0 taken 2031539 times.
✗ Branch 1 not taken.
2031572 my_free(mysql->options.extension->tls_ciphersuites);
3383
1/2
✓ Branch 0 taken 2031548 times.
✗ Branch 1 not taken.
2031539 my_free(mysql->options.extension->load_data_dir);
3384
2/2
✓ Branch 0 taken 6094616 times.
✓ Branch 1 taken 2031551 times.
8126167 for (unsigned int idx = 0; idx < MAX_AUTHENTICATION_FACTOR; idx++) {
3385
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6094616 times.
6094616 if (mysql->options.extension->client_auth_info[idx].plugin_name) {
3386 my_free(mysql->options.extension->client_auth_info[idx].plugin_name);
3387 mysql->options.extension->client_auth_info[idx].plugin_name = nullptr;
3388 }
3389
2/2
✓ Branch 0 taken 240862 times.
✓ Branch 1 taken 5853754 times.
6094616 if (mysql->options.extension->client_auth_info[idx].password) {
3390
1/2
✓ Branch 0 taken 240865 times.
✗ Branch 1 not taken.
240862 my_free(mysql->options.extension->client_auth_info[idx].password);
3391 240865 mysql->options.extension->client_auth_info[idx].password = nullptr;
3392 }
3393 }
3394 }
3395 2078296 mysql->options.ssl_key = nullptr;
3396 2078296 mysql->options.ssl_cert = nullptr;
3397 2078296 mysql->options.ssl_ca = nullptr;
3398 2078296 mysql->options.ssl_capath = nullptr;
3399 2078296 mysql->options.ssl_cipher = nullptr;
3400
2/2
✓ Branch 0 taken 2031563 times.
✓ Branch 1 taken 46733 times.
2078296 if (mysql->options.extension) {
3401 2031563 mysql->options.extension->ssl_crl = nullptr;
3402 2031563 mysql->options.extension->ssl_crlpath = nullptr;
3403 2031563 mysql->options.extension->ssl_ctx_flags = 0;
3404 2031563 mysql->options.extension->tls_version = nullptr;
3405 2031563 mysql->options.extension->ssl_mode = SSL_MODE_DISABLED;
3406 2031563 mysql->options.extension->ssl_fips_mode = SSL_FIPS_MODE_OFF;
3407 2031563 mysql->options.extension->tls_ciphersuites = nullptr;
3408 2031563 mysql->options.extension->load_data_dir = nullptr;
3409 }
3410 2078296 mysql->connector_fd = nullptr;
3411 2078296 }
3412
3413 /*
3414 Return the SSL cipher (if any) used for current
3415 connection to the server.
3416
3417 SYNOPSIS
3418 mysql_get_ssl_cipher()
3419 mysql pointer to the mysql connection
3420
3421 */
3422
3423 21593 const char *STDCALL mysql_get_ssl_cipher(MYSQL *mysql [[maybe_unused]]) {
3424
1/2
✓ Branch 0 taken 21594 times.
✗ Branch 1 not taken.
21593 DBUG_TRACE;
3425
3/4
✓ Branch 0 taken 21594 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21113 times.
✓ Branch 3 taken 481 times.
21594 if (mysql->net.vio && mysql->net.vio->ssl_arg)
3426
2/4
✓ Branch 0 taken 21113 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21112 times.
✗ Branch 3 not taken.
21113 return SSL_get_cipher_name((SSL *)mysql->net.vio->ssl_arg);
3427 481 return nullptr;
3428 21593 }
3429
3430 #include <openssl/x509v3.h>
3431
3432 #if OPENSSL_VERSION_NUMBER < 0x10002000L
3433 /*
3434 Compares the DNS entry from the Subject Alternative Names (SAN) list with
3435 the provided host name
3436
3437 SYNOPSIS
3438 ssl_cmp_san_dns_name()
3439 dns_name pointer to a SAN list DNS entry
3440 host_name name of the server
3441 errptr if we fail, we'll return (a pointer to a string
3442 describing) the reason here
3443
3444 RETURN VALUES
3445 false Success
3446 true Failed to validate server
3447
3448 */
3449
3450 static bool ssl_cmp_san_dns_name(ASN1_STRING *dns_name, const char *host_name,
3451 const char **errptr) {
3452 DBUG_ENTER("ssl_cmp_san_dns_name");
3453 *errptr = nullptr;
3454 if (dns_name == nullptr) {
3455 *errptr = "Failed to get DNS name from SAN list item";
3456 DBUG_RETURN(true);
3457 }
3458 #if OPENSSL_VERSION_NUMBER < 0x10100000L
3459 const char *cn = reinterpret_cast<const char *>(
3460 const_cast<const unsigned char *>(ASN1_STRING_data(dns_name)));
3461 #else
3462 const char *cn = static_cast<const char *>(ASN1_STRING_get0_data(dns_name));
3463 #endif
3464 if (cn == nullptr) {
3465 *errptr = "Failed to get data from SAN DNS name";
3466 DBUG_RETURN(true);
3467 }
3468 // There should not be any NULL embedded in the DNS name
3469 if (static_cast<size_t>(ASN1_STRING_length(dns_name)) != strlen(cn)) {
3470 *errptr = "NULL embedded in the certificate SAN DNS name";
3471 DBUG_RETURN(true);
3472 }
3473 DBUG_PRINT("info", ("SAN DNS name in cert: %s", cn));
3474 if (!strcmp(cn, host_name)) DBUG_RETURN(false);
3475
3476 DBUG_RETURN(true);
3477 }
3478
3479 /*
3480 Compares the IP address entry from the Subject Alternative Names (SAN) list
3481 with the provided host IP address
3482
3483 SYNOPSIS
3484 ssl_cmp_san_ip_address()
3485 ip_address pointer to a SAN list IP address entry
3486 host_ip IP address of the server
3487 host_ip_len server IP address length (must be either 4 or 16)
3488 errptr if we fail, we'll return (a pointer to a string
3489 describing) the reason here
3490
3491 RETURN VALUES
3492 false Success
3493 true Failed to validate server
3494
3495 */
3496
3497 static bool ssl_cmp_san_ip_address(ASN1_OCTET_STRING *ip_address,
3498 const unsigned char *host_ip,
3499 size_t host_ip_len, const char **errptr) {
3500 DBUG_ENTER("ssl_cmp_san_ip_address");
3501 *errptr = nullptr;
3502 if (ip_address == nullptr) {
3503 *errptr = "Failed to get IP address from SAN list item";
3504 DBUG_RETURN(true);
3505 }
3506 const size_t ip_address_len = ASN1_STRING_length(ip_address);
3507 /* IP address length must be either 4 (IPV4) or 16 (IPV6) */
3508 if (ip_address_len != 4 && ip_address_len != 16) {
3509 *errptr = "Invalid IP address embedded in the certificate SAN IP address";
3510 DBUG_RETURN(true);
3511 }
3512 #if OPENSSL_VERSION_NUMBER < 0x10100000L
3513 const unsigned char *ip = ASN1_STRING_data(ip_address);
3514 #else
3515 const unsigned char *ip = ASN1_STRING_get0_data(ip_address);
3516 #endif
3517 if (ip == nullptr) {
3518 *errptr = "Failed to get data from SAN IP address";
3519 DBUG_RETURN(true);
3520 }
3521 DBUG_RETURN(!(ip_address_len == host_ip_len &&
3522 memcmp(host_ip, ip, host_ip_len) == 0));
3523 }
3524
3525 /*
3526 Check the certificate's Subject Alternative Names (SAN) against the
3527 hostname / IP address we connected to
3528
3529 SYNOPSIS
3530 ssl_verify_server_cert_san()
3531 server_cert pointer to a X509 certificate
3532 hostname_or_ip name of the server / pointer to a V4/V6 IP address
3533 buffer
3534 hostname_or_ip_len 0 for host name, 4/16 for ip address
3535 errptr if we fail, we'll return (a pointer to a string
3536 describing) the reason here
3537
3538 RETURN VALUES
3539 false Success
3540 true Failed to validate server
3541
3542 */
3543
3544 static bool ssl_verify_server_cert_san(X509 *server_cert,
3545 const char *hostname_or_ip,
3546 size_t hostname_or_ip_len,
3547 const char **errptr) {
3548 bool ret_validation = true;
3549
3550 DBUG_ENTER("ssl_verify_server_cert_san");
3551 *errptr = nullptr;
3552 GENERAL_NAMES *const sans = static_cast<GENERAL_NAMES *>(
3553 X509_get_ext_d2i(server_cert, NID_subject_alt_name, nullptr, nullptr));
3554 if (sans == nullptr) DBUG_RETURN(ret_validation);
3555
3556 const int number_of_sans = sk_GENERAL_NAME_num(sans);
3557 for (int i = 0; ret_validation != 0 && i < number_of_sans; ++i) {
3558 GENERAL_NAME *san = sk_GENERAL_NAME_value(sans, i);
3559 if (san == nullptr) {
3560 *errptr = "Failed to get item from SAN list";
3561 goto error;
3562 }
3563 if (hostname_or_ip_len == 0) {
3564 /* server host name was provided, check only GEN_DNS entries */
3565 if (san->type == GEN_DNS) {
3566 ret_validation =
3567 ssl_cmp_san_dns_name(san->d.dNSName, hostname_or_ip, errptr);
3568 if (*errptr != nullptr) goto error;
3569 }
3570 } else {
3571 /* server IP address was provided, check only GEN_IPADD entries */
3572 if (san->type == GEN_IPADD) {
3573 ret_validation = ssl_cmp_san_ip_address(
3574 san->d.iPAddress,
3575 reinterpret_cast<const unsigned char *>(hostname_or_ip),
3576 hostname_or_ip_len, errptr);
3577 if (*errptr != NULL) goto error;
3578 }
3579 }
3580 } /* iterating over SAN enries */
3581
3582 error:
3583 GENERAL_NAMES_free(sans);
3584
3585 DBUG_RETURN(ret_validation);
3586 }
3587
3588 #endif /* OPENSSL_VERSION_NUMBER < 0x10002000L */
3589
3590 /**
3591 Get the current SSL session serialization
3592
3593 Return the SSL session serialized (if any) used for current
3594 connection to the server.
3595 The caller needs to free the return value by calling @ref
3596 mysql_free_ssl_session_data()
3597
3598 @param mysql pointer to the mysql connection
3599 @param n_ticket the ticket to return. Currently on 0 is supported.
3600 @param[out] out_len if a non-null is supplied, stores the length of data
3601 returned.
3602 @retval null-terminated string of the session serialization
3603 @retval null pointer if not an SSL connection or error
3604 */
3605
3606 26805 void *STDCALL mysql_get_ssl_session_data(MYSQL *mysql, unsigned int n_ticket,
3607 unsigned int *out_len) {
3608
1/2
✓ Branch 0 taken 26805 times.
✗ Branch 1 not taken.
26805 DBUG_TRACE;
3609
3610 /* multiple TLS ticket not implemented yet */
3611
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26805 times.
26805 if (n_ticket != 0) return nullptr;
3612
3613 using raii_bio = std::unique_ptr<BIO, decltype(&BIO_free)>;
3614 using raii_sess = std::unique_ptr<SSL_SESSION, decltype(&SSL_SESSION_free)>;
3615
3616
4/4
✓ Branch 0 taken 26804 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 16160 times.
✓ Branch 3 taken 10644 times.
26805 if (!mysql->net.vio || !mysql->net.vio->ssl_arg) {
3617
1/2
✓ Branch 0 taken 16161 times.
✗ Branch 1 not taken.
16161 set_mysql_extended_error(
3618 mysql, CR_CANT_GET_SESSION_DATA, unknown_sqlstate,
3619 ER_CLIENT(CR_CANT_GET_SESSION_DATA),
3620
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16160 times.
16161 !mysql->net.vio ? "Not connected" : "Not a TLS connection");
3621 16161 return nullptr;
3622 }
3623 raii_sess sess(
3624 10644 SSL_get1_session(reinterpret_cast<SSL *>(mysql->net.vio->ssl_arg)),
3625
1/2
✓ Branch 0 taken 10644 times.
✗ Branch 1 not taken.
10644 &SSL_SESSION_free);
3626
6/8
✓ Branch 0 taken 10644 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10644 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 10636 times.
✓ Branch 6 taken 8 times.
✓ Branch 7 taken 10636 times.
10644 if (!sess || !SSL_SESSION_is_resumable(sess.get())) {
3627
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 set_mysql_extended_error(
3628 mysql, CR_CANT_GET_SESSION_DATA, unknown_sqlstate,
3629 ER_CLIENT(CR_CANT_GET_SESSION_DATA),
3630
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 !sess ? "no session returned" : "session returned not resumable");
3631 8 return nullptr;
3632 }
3633
3634
2/4
✓ Branch 0 taken 10636 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10636 times.
✗ Branch 3 not taken.
10636 raii_bio bio(BIO_new(BIO_s_mem()), &BIO_free);
3635
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10636 times.
10636 if (!bio) {
3636 set_mysql_extended_error(mysql, CR_CANT_GET_SESSION_DATA, unknown_sqlstate,
3637 ER_CLIENT(CR_CANT_GET_SESSION_DATA),
3638 "Can't create the session data encoding object");
3639 return nullptr;
3640 }
3641
2/4
✓ Branch 0 taken 10636 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10636 times.
10636 if (0 == PEM_write_bio_SSL_SESSION(bio.get(), sess.get())) {
3642 set_mysql_extended_error(mysql, CR_CANT_GET_SESSION_DATA, unknown_sqlstate,
3643 ER_CLIENT(CR_CANT_GET_SESSION_DATA),
3644 "Can't encode the session data");
3645 return nullptr;
3646 }
3647
3648 10636 BUF_MEM *mem = nullptr;
3649
1/2
✓ Branch 0 taken 10636 times.
✗ Branch 1 not taken.
10636 BIO_get_mem_ptr(bio.get(), &mem);
3650
2/4
✓ Branch 0 taken 10636 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10636 times.
10636 if (!mem || mem->length == 0) {
3651 set_mysql_extended_error(mysql, CR_CANT_GET_SESSION_DATA, unknown_sqlstate,
3652 ER_CLIENT(CR_CANT_GET_SESSION_DATA),
3653 "Can't get a pointer to the session data");
3654 return nullptr;
3655 }
3656 char *ret = reinterpret_cast<char *>(
3657
1/2
✓ Branch 0 taken 10636 times.
✗ Branch 1 not taken.
10636 my_malloc(key_memory_MYSQL_ssl_session_data, mem->length + 1, MYF(0)));
3658 10636 memcpy(ret, mem->data, mem->length);
3659 10636 ret[mem->length] = 0;
3660
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 10635 times.
10636 if (out_len) *out_len = static_cast<unsigned int>(mem->length);
3661 10636 return ret;
3662 26805 }
3663
3664 47937 static SSL_SESSION *ssl_session_deserialize_from_data_ptr(MYSQL *, char *data) {
3665 using raii_bio = std::unique_ptr<BIO, decltype(&BIO_free)>;
3666
2/2
✓ Branch 0 taken 10678 times.
✓ Branch 1 taken 37259 times.
47937 if (data != nullptr) {
3667 10678 SSL_SESSION *ret = nullptr;
3668
1/2
✓ Branch 0 taken 10678 times.
✗ Branch 1 not taken.
10678 raii_bio bio(BIO_new_mem_buf(data, strlen(data)), &BIO_free);
3669
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10678 times.
10678 if (!bio) return ret;
3670
1/2
✓ Branch 0 taken 10678 times.
✗ Branch 1 not taken.
10678 ret = PEM_read_bio_SSL_SESSION(bio.get(), &ret, nullptr, nullptr);
3671
4/8
✓ Branch 0 taken 10678 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10678 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10678 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 10678 times.
10678 if (ret && !SSL_SESSION_is_resumable(ret)) {
3672 if (ret) SSL_SESSION_free(ret);
3673 ret = nullptr;
3674 }
3675 10678 return ret;
3676 10678 }
3677 37259 return nullptr;
3678 }
3679
3680 /**
3681 Free a saved SSL session serialization
3682
3683 Frees the session serialization as returned by @ref
3684 mysql_get_ssl_session_data()
3685
3686 @param mysql pointer to the mysql connection
3687 @param data the session data to dispose of
3688 @retval true failure
3689 @retval false success
3690 */
3691
3692 10636 bool STDCALL mysql_free_ssl_session_data(MYSQL *mysql, void *data) {
3693 10636 SSL_SESSION *ses = ssl_session_deserialize_from_data_ptr(
3694 mysql, reinterpret_cast<char *>(data));
3695 10636 my_free(data);
3696
1/2
✓ Branch 0 taken 10636 times.
✗ Branch 1 not taken.
10636 if (ses) {
3697 10636 SSL_SESSION_free(ses);
3698 10636 return false;
3699 } else
3700 return true;
3701 }
3702
3703 /**
3704 Check if the current ssl session is reused
3705
3706 @param mysql pointer to the mysql connection
3707 @retval false not SSL or session not reused
3708 @retval true session reused
3709 */
3710
3711 36 bool STDCALL mysql_get_ssl_session_reused(MYSQL *mysql) {
3712
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 DBUG_TRACE;
3713
3/4
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 2 times.
36 if (mysql->net.vio && mysql->net.vio->ssl_arg) {
3714 68 return SSL_session_reused(
3715
1/2
✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
34 reinterpret_cast<SSL *>(mysql->net.vio->ssl_arg)) != 0;
3716 }
3717 2 return false;
3718 36 }
3719
3720 /*
3721 Check the server's (subject) Common Name against the
3722 hostname we connected to
3723
3724 SYNOPSIS
3725 ssl_verify_server_cert()
3726 vio pointer to a SSL connected vio
3727 server_hostname name of the server that we connected to
3728 errptr if we fail, we'll return (a pointer to a string
3729 describing) the reason here
3730
3731 RETURN VALUES
3732 0 Success
3733 1 Failed to validate server
3734
3735 */
3736 22 static int ssl_verify_server_cert(Vio *vio, const char *server_hostname,
3737 const char **errptr) {
3738 SSL *ssl;
3739 22 X509 *server_cert = nullptr;
3740 #if OPENSSL_VERSION_NUMBER < 0x10002000L
3741 char *cn = NULL;
3742 int cn_loc = -1;
3743 ASN1_STRING *cn_asn1 = NULL;
3744 X509_NAME_ENTRY *cn_entry = NULL;
3745 X509_NAME *subject = NULL;
3746 const unsigned char *ipout = nullptr;
3747 size_t iplen = 0;
3748 #endif
3749 22 ASN1_OCTET_STRING *server_ip_address = nullptr;
3750 22 int ret_validation = 1;
3751
3752
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 DBUG_TRACE;
3753
3/8
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 22 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
22 DBUG_PRINT("enter", ("server_hostname: %s", server_hostname));
3754
3755
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
22 if (!(ssl = (SSL *)vio->ssl_arg)) {
3756 *errptr = "No SSL pointer found";
3757 goto error;
3758 }
3759
3760
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
22 if (!server_hostname) {
3761 *errptr = "No server hostname supplied";
3762 goto error;
3763 }
3764
3765
2/4
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
22 if (!(server_cert = SSL_get_peer_certificate(ssl))) {
3766 *errptr = "Could not get server certificate";
3767 goto error;
3768 }
3769
3770
2/4
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
22 if (X509_V_OK != SSL_get_verify_result(ssl)) {
3771 *errptr = "Failed to verify the server certificate";
3772 goto error;
3773 }
3774 /*
3775 We already know that the certificate exchanged was valid; the SSL library
3776 handled that. Now we need to verify that the contents of the certificate
3777 are what we expect.
3778 */
3779
3780 /* Use OpenSSL certificate matching functions instead of our own if we
3781 have OpenSSL. The X509_check_* functions return 1 on success.
3782 */
3783 #if OPENSSL_VERSION_NUMBER >= 0x10002000L
3784 /*
3785 For OpenSSL 1.0.2 and up we already set certificate verification
3786 parameters in the new_VioSSLFd() to perform automatic checks.
3787 */
3788 22 ret_validation = 0;
3789 #else /* OPENSSL_VERSION_NUMBER < 0x10002000L */
3790 /* Checking if the provided server_hostname is a V4/V6 IP address */
3791 server_ip_address = a2i_IPADDRESS(server_hostname);
3792 if (server_ip_address != nullptr) {
3793 iplen = ASN1_STRING_length(server_ip_address);
3794 ipout = (const unsigned char *)ASN1_STRING_data(server_ip_address);
3795 }
3796
3797 ret_validation = ssl_verify_server_cert_san(
3798 server_cert, iplen != 0 ? (const char *)ipout : server_hostname, iplen,
3799 errptr);
3800 if (*errptr != nullptr) goto error;
3801 if (ret_validation != 0) {
3802 /*
3803 OpenSSL prior to 1.0.2 do not support X509_check_host() function.
3804 Use deprecated X509_get_subject_name() instead.
3805 */
3806 subject = X509_get_subject_name(server_cert);
3807 // Find the CN location in the subject
3808 cn_loc = X509_NAME_get_index_by_NID(subject, NID_commonName, -1);
3809 if (cn_loc < 0) {
3810 *errptr = "Failed to get CN location in the certificate subject";
3811 goto error;
3812 }
3813
3814 // Get the CN entry for given location
3815 cn_entry = X509_NAME_get_entry(subject, cn_loc);
3816 if (cn_entry == nullptr) {
3817 *errptr = "Failed to get CN entry using CN location";
3818 goto error;
3819 }
3820
3821 // Get CN from common name entry
3822 cn_asn1 = X509_NAME_ENTRY_get_data(cn_entry);
3823 if (cn_asn1 == nullptr) {
3824 *errptr = "Failed to get CN from CN entry";
3825 goto error;
3826 }
3827
3828 cn = reinterpret_cast<char *>(ASN1_STRING_data(cn_asn1));
3829 if (cn == nullptr) {
3830 *errptr = "Failed to get data from CN";
3831 goto error;
3832 }
3833
3834 // There should not be any NULL embedded in the CN
3835 if (static_cast<size_t>(ASN1_STRING_length(cn_asn1)) != strlen(cn)) {
3836 *errptr = "NULL embedded in the certificate CN";
3837 goto error;
3838 }
3839
3840 DBUG_PRINT("info", ("Server hostname in cert: %s", cn));
3841 if (!strcmp(cn, server_hostname)) {
3842 /* Success */
3843 ret_validation = 0;
3844 }
3845 }
3846 #endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
3847
3848
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
22 *errptr = ret_validation != 0 ? "SSL certificate validation failure" : "";
3849
3850 22 error:
3851
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
22 if (server_ip_address != nullptr) ASN1_OCTET_STRING_free(server_ip_address);
3852
3853
2/4
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
✗ Branch 3 not taken.
22 if (server_cert != nullptr) X509_free(server_cert);
3854 22 return ret_validation;
3855 22 }
3856
3857 /*
3858 Note that the mysql argument must be initialized with mysql_init()
3859 before calling mysql_real_connect !
3860 */
3861
3862 static bool cli_read_query_result(MYSQL *mysql);
3863 static net_async_status cli_read_query_result_nonblocking(MYSQL *mysql);
3864 static MYSQL_RES *cli_use_result(MYSQL *mysql);
3865
3866 396190 int cli_read_change_user_result(MYSQL *mysql) {
3867 396190 return cli_safe_read(mysql, nullptr);
3868 }
3869
3870 12543 net_async_status cli_read_change_user_result_nonblocking(MYSQL *mysql,
3871 ulong *ret) {
3872 12543 return cli_safe_read_nonblocking(mysql, nullptr, ret);
3873 }
3874
3875 static MYSQL_METHODS client_methods = {
3876 cli_read_query_result, /* read_query_result */
3877 cli_advanced_command, /* advanced_command */
3878 cli_read_rows, /* read_rows */
3879 cli_use_result, /* use_result */
3880 cli_fetch_lengths, /* fetch_lengths */
3881 cli_flush_use_result, /* flush_use_result */
3882 cli_read_change_user_result /* read_change_user_result */
3883 #ifndef MYSQL_SERVER
3884 ,
3885 cli_list_fields, /* list_fields */
3886 cli_read_prepare_result, /* read_prepare_result */
3887 cli_stmt_execute, /* stmt_execute */
3888 cli_read_binary_rows, /* read_binary_rows */
3889 cli_unbuffered_fetch, /* unbuffered_fetch */
3890 cli_read_statistics, /* read_statistics */
3891 cli_read_query_result, /* next_result */
3892 cli_read_binary_rows, /* read_rows_from_cursor */
3893 free_rows
3894 #endif
3895 ,
3896 cli_read_query_result_nonblocking, /* read_query_result_nonblocking */
3897 cli_advanced_command_nonblocking, /* advanced_command_nonblocking */
3898 cli_read_rows_nonblocking, /* read_rows_nonblocking */
3899 cli_flush_use_result_nonblocking, /* flush_use_result_nonblocking */
3900 cli_read_query_result_nonblocking, /* next_result_nonblocking */
3901 cli_read_change_user_result_nonblocking /* read_change_user_result_nonblocking
3902 */
3903 };
3904
3905 typedef enum my_cs_match_type_enum {
3906 /* MySQL and OS charsets are fully compatible */
3907 my_cs_exact,
3908 /* MySQL charset is very close to OS charset */
3909 my_cs_approx,
3910 /*
3911 MySQL knows this charset, but it is not supported as client character set.
3912 */
3913 my_cs_unsupp
3914 } my_cs_match_type;
3915
3916 struct MY_CSET_OS_NAME {
3917 const char *os_name;
3918 const char *my_name;
3919 my_cs_match_type param;
3920 };
3921
3922 const MY_CSET_OS_NAME charsets[] = {
3923 #ifdef _WIN32
3924 {"cp437", "cp850", my_cs_approx}, {"cp850", "cp850", my_cs_exact},
3925 {"cp852", "cp852", my_cs_exact}, {"cp858", "cp850", my_cs_approx},
3926 {"cp866", "cp866", my_cs_exact}, {"cp874", "tis620", my_cs_approx},
3927 {"cp932", "cp932", my_cs_exact}, {"cp936", "gbk", my_cs_approx},
3928 {"cp949", "euckr", my_cs_approx}, {"cp950", "big5", my_cs_exact},
3929 {"cp1200", "utf16le", my_cs_unsupp}, {"cp1201", "utf16", my_cs_unsupp},
3930 {"cp1250", "cp1250", my_cs_exact}, {"cp1251", "cp1251", my_cs_exact},
3931 {"cp1252", "latin1", my_cs_exact}, {"cp1253", "greek", my_cs_exact},
3932 {"cp1254", "latin5", my_cs_exact}, {"cp1255", "hebrew", my_cs_approx},
3933 {"cp1256", "cp1256", my_cs_exact}, {"cp1257", "cp1257", my_cs_exact},
3934 {"cp10000", "macroman", my_cs_exact}, {"cp10001", "sjis", my_cs_approx},
3935 {"cp10002", "big5", my_cs_approx}, {"cp10008", "gb2312", my_cs_approx},
3936 {"cp10021", "tis620", my_cs_approx}, {"cp10029", "macce", my_cs_exact},
3937 {"cp12001", "utf32", my_cs_unsupp}, {"cp20107", "swe7", my_cs_exact},
3938 {"cp20127", "latin1", my_cs_approx}, {"cp20866", "koi8r", my_cs_exact},
3939 {"cp20932", "ujis", my_cs_exact}, {"cp20936", "gb2312", my_cs_approx},
3940 {"cp20949", "euckr", my_cs_approx}, {"cp21866", "koi8u", my_cs_exact},
3941 {"cp28591", "latin1", my_cs_approx}, {"cp28592", "latin2", my_cs_exact},
3942 {"cp28597", "greek", my_cs_exact}, {"cp28598", "hebrew", my_cs_exact},
3943 {"cp28599", "latin5", my_cs_exact}, {"cp28603", "latin7", my_cs_exact},
3944 {"cp38598", "hebrew", my_cs_exact}, {"cp51932", "ujis", my_cs_exact},
3945 {"cp51936", "gb2312", my_cs_exact}, {"cp51949", "euckr", my_cs_exact},
3946 {"cp51950", "big5", my_cs_exact}, {"cp54936", "gb18030", my_cs_exact},
3947 {"cp65001", "utf8mb4", my_cs_exact},
3948
3949 #else /* not Windows */
3950
3951 {"646", "latin1", my_cs_approx}, /* Default on Solaris */
3952 {"ANSI_X3.4-1968", "latin1", my_cs_approx},
3953 {"ansi1251", "cp1251", my_cs_exact},
3954 {"armscii8", "armscii8", my_cs_exact},
3955 {"armscii-8", "armscii8", my_cs_exact},
3956 {"ASCII", "latin1", my_cs_approx},
3957 {"Big5", "big5", my_cs_exact},
3958 {"cp1251", "cp1251", my_cs_exact},
3959 {"cp1255", "hebrew", my_cs_approx},
3960 {"CP866", "cp866", my_cs_exact},
3961 {"eucCN", "gb2312", my_cs_exact},
3962 {"euc-CN", "gb2312", my_cs_exact},
3963 {"eucJP", "ujis", my_cs_exact},
3964 {"euc-JP", "ujis", my_cs_exact},
3965 {"eucKR", "euckr", my_cs_exact},
3966 {"euc-KR", "euckr", my_cs_exact},
3967 {"gb18030", "gb18030", my_cs_exact},
3968 {"gb2312", "gb2312", my_cs_exact},
3969 {"gbk", "gbk", my_cs_exact},
3970 {"georgianps", "geostd8", my_cs_exact},
3971 {"georgian-ps", "geostd8", my_cs_exact},
3972 {"IBM-1252", "cp1252", my_cs_exact},
3973
3974 {"iso88591", "latin1", my_cs_approx},
3975 {"ISO_8859-1", "latin1", my_cs_approx},
3976 {"ISO8859-1", "latin1", my_cs_approx},
3977 {"ISO-8859-1", "latin1", my_cs_approx},
3978
3979 {"iso885913", "latin7", my_cs_exact},
3980 {"ISO_8859-13", "latin7", my_cs_exact},
3981 {"ISO8859-13", "latin7", my_cs_exact},
3982 {"ISO-8859-13", "latin7", my_cs_exact},
3983
3984 {"iso88592", "latin2", my_cs_exact},
3985 {"ISO_8859-2", "latin2", my_cs_exact},
3986 {"ISO8859-2", "latin2", my_cs_exact},
3987 {"ISO-8859-2", "latin2", my_cs_exact},
3988
3989 {"iso88597", "greek", my_cs_exact},
3990 {"ISO_8859-7", "greek", my_cs_exact},
3991 {"ISO8859-7", "greek", my_cs_exact},
3992 {"ISO-8859-7", "greek", my_cs_exact},
3993
3994 {"iso88598", "hebrew", my_cs_exact},
3995 {"ISO_8859-8", "hebrew", my_cs_exact},
3996 {"ISO8859-8", "hebrew", my_cs_exact},
3997 {"ISO-8859-8", "hebrew", my_cs_exact},
3998
3999 {"iso88599", "latin5", my_cs_exact},
4000 {"ISO_8859-9", "latin5", my_cs_exact},
4001 {"ISO8859-9", "latin5", my_cs_exact},
4002 {"ISO-8859-9", "latin5", my_cs_exact},
4003
4004 {"koi8r", "koi8r", my_cs_exact},
4005 {"KOI8-R", "koi8r", my_cs_exact},
4006 {"koi8u", "koi8u", my_cs_exact},
4007 {"KOI8-U", "koi8u", my_cs_exact},
4008
4009 {"roman8", "hp8", my_cs_exact}, /* Default on HP UX */
4010
4011 {"Shift_JIS", "sjis", my_cs_exact},
4012 {"SJIS", "sjis", my_cs_exact},
4013 {"shiftjisx0213", "sjis", my_cs_exact},
4014
4015 {"tis620", "tis620", my_cs_exact},
4016 {"tis-620", "tis620", my_cs_exact},
4017
4018 {"ujis", "ujis", my_cs_exact},
4019
4020 {"US-ASCII", "latin1", my_cs_approx},
4021
4022 {"utf8", "utf8mb4", my_cs_exact},
4023 {"utf-8", "utf8mb4", my_cs_exact},
4024 #endif
4025 {nullptr, nullptr, my_cs_exact}};
4026
4027 4961 const char *my_os_charset_to_mysql_charset(const char *csname) {
4028 const MY_CSET_OS_NAME *csp;
4029
1/2
✓ Branch 0 taken 9922 times.
✗ Branch 1 not taken.
9922 for (csp = charsets; csp->os_name; csp++) {
4030
2/2
✓ Branch 0 taken 4961 times.
✓ Branch 1 taken 4961 times.
9922 if (!my_strcasecmp(&my_charset_latin1, csp->os_name, csname)) {
4031
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 4961 times.
✗ Branch 2 not taken.
4961 switch (csp->param) {
4032 case my_cs_exact:
4033 return csp->my_name;
4034
4035 4961 case my_cs_approx:
4036 /*
4037 Maybe we should print a warning eventually:
4038 character set correspondence is not exact.
4039 */
4040 4961 return csp->my_name;
4041
4042 default:
4043 my_printf_error(ER_UNKNOWN_ERROR,
4044 "OS character set '%s'"
4045 " is not supported by MySQL client",
4046 MYF(0), csp->my_name);
4047 goto def;
4048 }
4049 }
4050 }
4051
4052 my_printf_error(ER_UNKNOWN_ERROR, "Unknown OS character set '%s'.", MYF(0),
4053 csname);
4054
4055 def:
4056 csname = MYSQL_DEFAULT_CHARSET_NAME;
4057 my_printf_error(ER_UNKNOWN_ERROR,
4058 "Switching to the default character set '%s'.", MYF(0),
4059 csname);
4060 return csname;
4061 }
4062
4063 #ifndef _WIN32
4064 #include <stdlib.h> /* for getenv() */
4065 #ifdef HAVE_LANGINFO_H
4066 #include <langinfo.h>
4067 #endif
4068 #include <locale.h>
4069 #endif /* _WIN32 */
4070
4071 4961 static int mysql_autodetect_character_set(MYSQL *mysql) {
4072 4961 const char *csname = MYSQL_DEFAULT_CHARSET_NAME;
4073
4074 #ifdef _WIN32
4075 char cpbuf[64];
4076 {
4077 snprintf(cpbuf, sizeof(cpbuf), "cp%d", (int)GetConsoleCP());
4078 csname = my_os_charset_to_mysql_charset(cpbuf);
4079 }
4080 #elif defined(HAVE_NL_LANGINFO)
4081 {
4082
3/6
✓ Branch 0 taken 4961 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4961 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4961 times.
✗ Branch 5 not taken.
4961 if (setlocale(LC_CTYPE, "") && (csname = nl_langinfo(CODESET)))
4083 4961 csname = my_os_charset_to_mysql_charset(csname);
4084 }
4085 #endif
4086
4087
1/2
✓ Branch 0 taken 4961 times.
✗ Branch 1 not taken.
4961 if (mysql->options.charset_name) my_free(mysql->options.charset_name);
4088 4961 if (!(mysql->options.charset_name =
4089
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4961 times.
4961 my_strdup(key_memory_mysql_options, csname, MYF(MY_WME))))
4090 return 1;
4091 4961 return 0;
4092 }
4093
4094 410284 static void mysql_set_character_set_with_default_collation(MYSQL *mysql) {
4095 410284 const char *save = charsets_dir;
4096
2/2
✓ Branch 0 taken 70786 times.
✓ Branch 1 taken 339498 times.
410284 if (mysql->options.charset_dir) {
4097 #ifdef MYSQL_SERVER
4098 // Do not change charsets_dir, it is not thread safe.
4099 assert(false);
4100 #else
4101 70786 charsets_dir = mysql->options.charset_dir;
4102 #endif
4103 }
4104
2/2
✓ Branch 0 taken 410367 times.
✓ Branch 1 taken 24 times.
410284 if ((mysql->charset = get_charset_by_csname(mysql->options.charset_name,
4105 MY_CS_PRIMARY, MYF(MY_WME)))) {
4106 /* Try to set compiled default collation when it's possible. */
4107 CHARSET_INFO *collation;
4108 410356 if ((collation =
4109
4/4
✓ Branch 0 taken 410307 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 405084 times.
✓ Branch 3 taken 5272 times.
820699 get_charset_by_name(MYSQL_DEFAULT_COLLATION_NAME, MYF(MY_WME))) &&
4110
2/2
✓ Branch 0 taken 405116 times.
✓ Branch 1 taken 5216 times.
410307 my_charset_same(mysql->charset, collation)) {
4111 405084 mysql->charset = collation;
4112 } else {
4113 /*
4114 Default compiled collation not found, or is not applicable
4115 to the requested character set.
4116 Continue with the default collation of the character set.
4117 */
4118 }
4119 }
4120 410380 charsets_dir = save;
4121 410380 }
4122
4123 410279 int mysql_init_character_set(MYSQL *mysql) {
4124 /* Set character set */
4125
2/2
✓ Branch 0 taken 227105 times.
✓ Branch 1 taken 183174 times.
410279 if (!mysql->options.charset_name) {
4126 227086 if (!(mysql->options.charset_name =
4127
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 227086 times.
227105 my_strdup(key_memory_mysql_options, MYSQL_DEFAULT_CHARSET_NAME,
4128 MYF(MY_WME))))
4129 return 1;
4130 366348 } else if (!strcmp(mysql->options.charset_name,
4131
3/4
✓ Branch 0 taken 4961 times.
✓ Branch 1 taken 178213 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 183174 times.
188135 MYSQL_AUTODETECT_CHARSET_NAME) &&
4132
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4961 times.
4961 mysql_autodetect_character_set(mysql))
4133 return 1;
4134
4135 410260 mysql_set_character_set_with_default_collation(mysql);
4136
4137
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 410330 times.
410330 if (!mysql->charset) {
4138 if (mysql->options.charset_dir)
4139 set_mysql_extended_error(mysql, CR_CANT_READ_CHARSET, unknown_sqlstate,
4140 ER_CLIENT(CR_CANT_READ_CHARSET),
4141 mysql->options.charset_name,
4142 mysql->options.charset_dir);
4143 else {
4144 char cs_dir_name[FN_REFLEN];
4145 get_charsets_dir(cs_dir_name);
4146 set_mysql_extended_error(mysql, CR_CANT_READ_CHARSET, unknown_sqlstate,
4147 ER_CLIENT(CR_CANT_READ_CHARSET),
4148 mysql->options.charset_name, cs_dir_name);
4149 }
4150 return 1;
4151 }
4152 410330 return 0;
4153 }
4154
4155 /*********** client side authentication support **************************/
4156
4157 static int client_mpvio_write_packet(MYSQL_PLUGIN_VIO *, const uchar *, int);
4158 static net_async_status client_mpvio_write_packet_nonblocking(
4159 struct MYSQL_PLUGIN_VIO *, const uchar *, int, int *);
4160 static int native_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
4161 static net_async_status native_password_auth_client_nonblocking(
4162 MYSQL_PLUGIN_VIO *vio, MYSQL *mysql, int *result);
4163 static int clear_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
4164
4165 static auth_plugin_t native_password_client_plugin = {
4166 MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
4167 MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION,
4168 native_password_plugin_name,
4169 MYSQL_CLIENT_PLUGIN_AUTHOR_ORACLE,
4170 "Native MySQL authentication",
4171 {1, 0, 0},
4172 "GPL",
4173 nullptr,
4174 nullptr,
4175 nullptr,
4176 nullptr,
4177 nullptr,
4178 native_password_auth_client,
4179 native_password_auth_client_nonblocking};
4180
4181 static auth_plugin_t clear_password_client_plugin = {
4182 MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
4183 MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION,
4184 "mysql_clear_password",
4185 MYSQL_CLIENT_PLUGIN_AUTHOR_ORACLE,
4186 "Clear password authentication plugin",
4187 {0, 1, 0},
4188 "GPL",
4189 nullptr,
4190 nullptr,
4191 nullptr,
4192 nullptr,
4193 nullptr,
4194 clear_password_auth_client,
4195 nullptr};
4196
4197 static auth_plugin_t sha256_password_client_plugin = {
4198 MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
4199 MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION,
4200 "sha256_password",
4201 MYSQL_CLIENT_PLUGIN_AUTHOR_ORACLE,
4202 "SHA256 based authentication with salt",
4203 {1, 0, 0},
4204 "GPL",
4205 nullptr,
4206 sha256_password_init,
4207 sha256_password_deinit,
4208 nullptr,
4209 nullptr,
4210 sha256_password_auth_client,
4211 sha256_password_auth_client_nonblocking};
4212
4213 static auth_plugin_t caching_sha2_password_client_plugin = {
4214 MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
4215 MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION,
4216 caching_sha2_password_plugin_name,
4217 MYSQL_CLIENT_PLUGIN_AUTHOR_ORACLE,
4218 "SHA2 based authentication with salt",
4219 {1, 0, 0},
4220 "GPL",
4221 nullptr,
4222 caching_sha2_password_init,
4223 caching_sha2_password_deinit,
4224 nullptr,
4225 nullptr,
4226 caching_sha2_password_auth_client,
4227 caching_sha2_password_auth_client_nonblocking};
4228 #ifdef AUTHENTICATION_WIN
4229 extern "C" auth_plugin_t win_auth_client_plugin;
4230 #endif
4231
4232 /*
4233 Test trace plugin can be used only in debug builds. In non-debug ones
4234 it is ignored, even if it was enabled by build options (TEST_TRACE_PLUGIN
4235 macro).
4236 */
4237
4238 #if defined(CLIENT_PROTOCOL_TRACING) && defined(TEST_TRACE_PLUGIN) && \
4239 !defined(NDEBUG)
4240 extern auth_plugin_t test_trace_plugin;
4241 #endif
4242
4243 struct st_mysql_client_plugin *mysql_client_builtins[] = {
4244 (struct st_mysql_client_plugin *)&native_password_client_plugin,
4245 (struct st_mysql_client_plugin *)&clear_password_client_plugin,
4246 (struct st_mysql_client_plugin *)&sha256_password_client_plugin,
4247 (struct st_mysql_client_plugin *)&caching_sha2_password_client_plugin,
4248 #ifdef AUTHENTICATION_WIN
4249 (struct st_mysql_client_plugin *)&win_auth_client_plugin,
4250 #endif
4251 #if defined(CLIENT_PROTOCOL_TRACING) && defined(TEST_TRACE_PLUGIN) && \
4252 !defined(NDEBUG)
4253 (struct st_mysql_client_plugin *)&test_trace_plugin,
4254 #endif
4255 nullptr};
4256
4257 4229163 static uchar *write_length_encoded_string3(uchar *buf, const char *string,
4258 size_t length) {
4259 4229163 buf = net_store_length(buf, length);
4260 4229273 memcpy(buf, string, length);
4261 4229273 buf += length;
4262 4229273 return buf;
4263 }
4264
4265 /*
4266 The main purpose of this is to hide C++ from st_mysql_options_extention.
4267 */
4268 struct My_hash {
4269 malloc_unordered_map<string, string> hash{key_memory_mysql_options};
4270 };
4271
4272 383060 uchar *send_client_connect_attrs(MYSQL *mysql, uchar *buf) {
4273 /* check if the server supports connection attributes */
4274
1/2
✓ Branch 0 taken 383093 times.
✗ Branch 1 not taken.
383060 if (mysql->server_capabilities & CLIENT_CONNECT_ATTRS) {
4275 /* Always store the length if the client supports it */
4276 383093 buf = net_store_length(
4277
1/2
✓ Branch 0 taken 383101 times.
✗ Branch 1 not taken.
383093 buf, mysql->options.extension
4278 383101 ? mysql->options.extension->connection_attributes_length
4279 : 0);
4280
4281 /* check if we have connection attributes */
4282
2/2
✓ Branch 0 taken 383088 times.
✓ Branch 1 taken 19 times.
383107 if (mysql->options.extension &&
4283
1/2
✓ Branch 0 taken 383109 times.
✗ Branch 1 not taken.
383088 mysql->options.extension->connection_attributes) {
4284 /* loop over and dump the connection attributes */
4285 383094 for (const auto &key_and_value :
4286
2/2
✓ Branch 0 taken 2114568 times.
✓ Branch 1 taken 383126 times.
2880968 mysql->options.extension->connection_attributes->hash) {
4287 2114588 const string &key = key_and_value.first;
4288 2114588 const string &value = key_and_value.second;
4289
4290 /* we can't have zero length keys */
4291
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2114649 times.
2114588 assert(!key.empty());
4292
4293
1/2
✓ Branch 0 taken 2114690 times.
✗ Branch 1 not taken.
2114649 buf = write_length_encoded_string3(buf, key.data(), key.size());
4294
1/2
✓ Branch 0 taken 2114747 times.
✗ Branch 1 not taken.
2114690 buf = write_length_encoded_string3(buf, value.data(), value.size());
4295 }
4296 }
4297 }
4298 383091 return buf;
4299 }
4300
4301 37631711 static size_t get_length_store_length(size_t length) {
4302 /* as defined in net_store_length */
4303 #define MAX_VARIABLE_STRING_LENGTH 9
4304 uchar length_buffer[MAX_VARIABLE_STRING_LENGTH], *ptr;
4305
4306
1/2
✓ Branch 0 taken 37632322 times.
✗ Branch 1 not taken.
37631711 ptr = net_store_length(length_buffer, length);
4307
4308 37632322 return ptr - &length_buffer[0];
4309 }
4310
4311 /*
4312 Write 1-8 bytes of string length header information to dest depending on
4313 value of src_len, then copy src_len bytes from src to dest.
4314
4315 @param dest Destination buffer of size src_len+8
4316 @param dest_end One byte past the end of the dest buffer
4317 @param src Source buff of size src_len
4318 @param src_end One byte past the end of the src buffer
4319
4320 @return pointer dest+src_len+header size or NULL if
4321 */
4322
4323 380855 static char *write_length_encoded_string4(char *dest, char *dest_end,
4324 const uchar *src,
4325 const uchar *src_end) {
4326 380855 size_t src_len = (size_t)(src_end - src);
4327 380855 uchar *to = net_store_length((uchar *)dest, src_len);
4328
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 380881 times.
380881 if ((char *)(to + src_len) >= dest_end) return nullptr;
4329 380881 memcpy(to, src, src_len);
4330 380881 return (char *)(to + src_len);
4331 }
4332
4333 /*
4334 Write 1 byte of string length header information to dest and
4335 copy src_len bytes from src to dest.
4336 */
4337 static char *write_string(char *dest, char *dest_end, const uchar *src,
4338 const uchar *src_end) {
4339 size_t src_len = (size_t)(src_end - src);
4340 uchar *to = nullptr;
4341 if (src_len >= 251) return nullptr;
4342 *dest = (uchar)src_len;
4343 to = (uchar *)dest + 1;
4344 if ((char *)(to + src_len) >= dest_end) return nullptr;
4345 memcpy(to, src, src_len);
4346 return (char *)(to + src_len);
4347 }
4348 /**
4349 Sends a @ref page_protocol_com_change_user
4350 with a caller provided payload
4351
4352 @retval 0 ok
4353 @retval 1 error
4354 */
4355 305 static int send_change_user_packet(MCPVIO_EXT *mpvio, const uchar *data,
4356 int data_len) {
4357 305 MYSQL *mysql = mpvio->mysql;
4358 char *buff, *end;
4359 305 int res = 1;
4360 305 size_t connect_attrs_len =
4361 610 (mysql->server_capabilities & CLIENT_CONNECT_ATTRS &&
4362
1/2
✓ Branch 0 taken 305 times.
✗ Branch 1 not taken.
305 mysql->options.extension)
4363
1/2
✓ Branch 0 taken 305 times.
✗ Branch 1 not taken.
610 ? mysql->options.extension->connection_attributes_length
4364 : 0;
4365
4366 buff = static_cast<char *>(
4367 305 my_alloca(USERNAME_LENGTH + data_len + 1 + NAME_LEN + 2 + NAME_LEN +
4368 connect_attrs_len + 9 /* for the length of the attrs */));
4369
4370 305 end = strmake(buff, mysql->user, USERNAME_LENGTH) + 1;
4371
4372
1/2
✓ Branch 0 taken 305 times.
✗ Branch 1 not taken.
305 if (!data_len)
4373 305 *end++ = 0;
4374 else {
4375 assert(data_len <= 255);
4376 if (data_len > 255) {
4377 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
4378 goto error;
4379 }
4380 *end++ = data_len;
4381 memcpy(end, data, data_len);
4382 end += data_len;
4383 }
4384
2/2
✓ Branch 0 taken 292 times.
✓ Branch 1 taken 13 times.
305 end = strmake(end, mpvio->db ? mpvio->db : "", NAME_LEN) + 1;
4385
4386
1/2
✓ Branch 0 taken 305 times.
✗ Branch 1 not taken.
305 if (mysql->server_capabilities & CLIENT_PROTOCOL_41) {
4387 305 int2store((uchar *)end, (ushort)mysql->charset->number);
4388 305 end += 2;
4389 }
4390
4391
1/2
✓ Branch 0 taken 305 times.
✗ Branch 1 not taken.
305 if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH)
4392 305 end = strmake(end, mpvio->plugin->name, NAME_LEN) + 1;
4393
4394 305 end = (char *)send_client_connect_attrs(mysql, (uchar *)end);
4395
4396
1/2
✓ Branch 0 taken 305 times.
✗ Branch 1 not taken.
305 res = simple_command(mysql, COM_CHANGE_USER, (uchar *)buff,
4397 (ulong)(end - buff), 1);
4398
4399 305 error:
4400 305 return res;
4401 }
4402
4403 /* clang-format off */
4404 /**
4405 @page page_protocol_connection_phase_packets_protocol_ssl_request Protocol::SSLRequest:
4406
4407 SSL Connection Request Packet. It is like
4408 @ref page_protocol_connection_phase_packets_protocol_handshake_response but is
4409 truncated right before username field. If server supports ::CLIENT_SSL
4410 capability, client can send this packet to request a secure SSL connection.
4411 The ::CLIENT_SSL capability flag must be set inside the SSL Connection Request Packet.
4412
4413 <table>
4414 <caption>Payload</caption>
4415 <tr><th>Type</th><th>Name</th><th>Description</th></tr>
4416 <tr><td colspan="3">if capabilities @& ::CLIENT_PROTOCOL_41 {</td></tr>
4417 <tr><td>@ref a_protocol_type_int4 "int&lt;4&gt;"</td>
4418 <td>client_flag</td>
4419 <td>\ref group_cs_capabilities_flags</td></tr>
4420 <tr><td>@ref a_protocol_type_int4 "int&lt;4&gt;"</td>
4421 <td>max_packet_size</td>
4422 <td>maximum packet size</td></tr>
4423 <tr><td>@ref a_protocol_type_int1 "int&lt;1&gt;"</td>
4424 <td>character_set</td>
4425 <td>client charset \ref a_protocol_character_set, only the lower 8-bits</td></tr>
4426 <tr><td>@ref sect_protocol_basic_dt_string_fix "string[23]"</td>
4427 <td>filler</td>
4428 <td>filler to the size of the handhshake response packet. All 0s.</td></tr>
4429 <tr><td colspan="3">} else {</td></tr>
4430 <tr><td>@ref a_protocol_type_int2 "int&lt;2&gt;"</td>
4431 <td>client_flag</td>
4432 <td>\ref group_cs_capabilities_flags, only the lower 16 bits</td></tr>
4433 <tr><td>@ref a_protocol_type_int3 "int&lt;3&gt;"</td>
4434 <td>max_packet_size</td>
4435 <td>maximum packet size, 0xFFFFFF max</td></tr>
4436 <tr><td colspan="3">}</td></tr>
4437 </table>
4438
4439 @sa int2store(), int3store(), int4store(), mysql_fill_packet_header()
4440 */
4441 /* clang-format on */
4442 /**
4443 Fill in the beginning of the client reply packet.
4444
4445 Used to fill in the beginning of the client reply packet
4446 or the ssl request packet.
4447
4448 @param mysql The mysql handler to operate
4449 @param[out] buff The buffer to receive the packet
4450 @param buff_size The max size of the buffer. Used in debug only.
4451 @return one past to where the buffer is filled
4452
4453 @sa page_protocol_conn_packets_protocol_ssl_request
4454 send_client_reply_packet()
4455 */
4456 402713 static char *mysql_fill_packet_header(MYSQL *mysql, char *buff,
4457 size_t buff_size [[maybe_unused]]) {
4458 402713 NET *net = &mysql->net;
4459 char *end;
4460 402713 uchar *buff_p = (uchar *)buff;
4461 /*
4462 Always send CLIENT_LOCAL_FILES to the server.
4463 This needs to be done since the client can always decide to support
4464 local files even if this option is disabled by enabling the directory.
4465 But we can't turn it on in the client flag since it's used throughout the
4466 code base if the option is enabled or not.
4467 */
4468 402713 unsigned long client_flag = mysql->client_flag | CLIENT_LOCAL_FILES;
4469
4470
1/2
✓ Branch 0 taken 402724 times.
✗ Branch 1 not taken.
402713 if (client_flag & CLIENT_PROTOCOL_41) {
4471 /* 4.1 server and 4.1 client has a 32 byte option flag */
4472
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 402724 times.
402724 assert(buff_size >= 32);
4473
4474 402724 int4store(buff_p, client_flag);
4475 402734 int4store(buff_p + 4, net->max_packet_size);
4476 402730 buff[8] = (char)mysql->charset->number;
4477 402730 memset(buff + 9, 0, 32 - 9);
4478 402730 end = buff + 32;
4479 } else {
4480 assert(buff_size >= 5);
4481 assert(client_flag <= UINT_MAX16);
4482
4483 int2store(buff_p, (uint16)client_flag);
4484 int3store(buff_p + 2, net->max_packet_size);
4485 end = buff + 5;
4486 }
4487 402690 return end;
4488 }
4489
4490 /**
4491 Calculates client capabilities in effect (mysql->client_flag)
4492
4493 Needs to be called immediately after receiving the server handshake packet.
4494
4495 @param mysql the connection context
4496 @param db The database specified by the client app
4497 @param client_flag The client flag as specified by the client app
4498 */
4499
4500 382891 static void cli_calculate_client_flag(MYSQL *mysql, const char *db,
4501 ulong client_flag) {
4502 382891 mysql->client_flag = client_flag;
4503 382891 mysql->client_flag |= mysql->options.client_flag;
4504 382891 mysql->client_flag |= CLIENT_CAPABILITIES;
4505
4506
2/2
✓ Branch 0 taken 346557 times.
✓ Branch 1 taken 36334 times.
382891 if (mysql->client_flag & CLIENT_MULTI_STATEMENTS)
4507 346557 mysql->client_flag |= CLIENT_MULTI_RESULTS;
4508
4509
1/2
✓ Branch 0 taken 382991 times.
✗ Branch 1 not taken.
382891 if (mysql->options.extension &&
4510
2/2
✓ Branch 0 taken 264412 times.
✓ Branch 1 taken 118579 times.
382991 mysql->options.extension->ssl_mode != SSL_MODE_DISABLED)
4511 264412 mysql->client_flag |= CLIENT_SSL;
4512
4513
2/2
✓ Branch 0 taken 287009 times.
✓ Branch 1 taken 95882 times.
382891 if (db)
4514 287009 mysql->client_flag |= CLIENT_CONNECT_WITH_DB;
4515 else
4516 95882 mysql->client_flag &= ~CLIENT_CONNECT_WITH_DB;
4517
4518 /* Remove options that server doesn't support */
4519 382891 mysql->client_flag = mysql->client_flag &
4520 (~(CLIENT_COMPRESS | CLIENT_SSL | CLIENT_PROTOCOL_41 |
4521 382891 CLIENT_OPTIONAL_RESULTSET_METADATA) |
4522 382891 mysql->server_capabilities);
4523
4524
2/2
✓ Branch 0 taken 302788 times.
✓ Branch 1 taken 80103 times.
382891 if (mysql->options.protocol == MYSQL_PROTOCOL_SOCKET &&
4525
1/2
✓ Branch 0 taken 302798 times.
✗ Branch 1 not taken.
302788 mysql->options.extension &&
4526
2/2
✓ Branch 0 taken 298016 times.
✓ Branch 1 taken 4782 times.
302798 mysql->options.extension->ssl_mode <= SSL_MODE_PREFERRED) {
4527 298016 mysql->client_flag &= ~CLIENT_SSL;
4528 298016 mysql->options.extension->ssl_mode = SSL_MODE_DISABLED;
4529 }
4530 382891 }
4531
4532 37302 static SSL_SESSION *ssl_session_deserialize_from_data(MYSQL *mysql) {
4533 74603 return ssl_session_deserialize_from_data_ptr(
4534 mysql,
4535 37302 reinterpret_cast<char *>(mysql->options.extension->ssl_session_data));
4536 }
4537
4538 /**
4539 Establishes SSL if requested and supported.
4540
4541 @param mysql the connection handle
4542 @retval 0 success
4543 @retval 1 failure
4544 */
4545 382851 static int cli_establish_ssl(MYSQL *mysql) {
4546 382851 NET *net = &mysql->net;
4547
4548 /* Don't fallback on unencrypted connection if SSL required. */
4549
1/2
✓ Branch 0 taken 382884 times.
✗ Branch 1 not taken.
382851 if (mysql->options.extension &&
4550
2/2
✓ Branch 0 taken 5383 times.
✓ Branch 1 taken 377501 times.
382884 mysql->options.extension->ssl_mode >= SSL_MODE_REQUIRED &&
4551
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 5342 times.
5383 !(mysql->server_capabilities & CLIENT_SSL)) {
4552 41 set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
4553 ER_CLIENT(CR_SSL_CONNECTION_ERROR),
4554 "SSL is required but the server doesn't "
4555 "support it");
4556 41 goto error;
4557 }
4558
4559 /*
4560 If the ssl_mode is VERIFY_CA or VERIFY_IDENTITY, make sure that the
4561 connection doesn't succeed without providing the CA certificate.
4562 */
4563
1/2
✓ Branch 0 taken 382835 times.
✗ Branch 1 not taken.
382810 if (mysql->options.extension &&
4564
2/2
✓ Branch 0 taken 379 times.
✓ Branch 1 taken 382456 times.
382835 mysql->options.extension->ssl_mode > SSL_MODE_REQUIRED &&
4565
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 377 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
379 !(mysql->options.ssl_ca || mysql->options.ssl_capath)) {
4566 2 set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
4567 ER_CLIENT(CR_SSL_CONNECTION_ERROR),
4568 "CA certificate is required if ssl-mode "
4569 "is VERIFY_CA or VERIFY_IDENTITY");
4570 2 goto error;
4571 }
4572
4573 /*
4574 Attempt SSL connection if ssl_mode != SSL_MODE_DISABLED and the
4575 server supports SSL. Fallback on unencrypted connection otherwise.
4576 */
4577
1/2
✓ Branch 0 taken 382846 times.
✗ Branch 1 not taken.
382808 if (mysql->options.extension &&
4578
2/2
✓ Branch 0 taken 37004 times.
✓ Branch 1 taken 345842 times.
382846 mysql->options.extension->ssl_mode != SSL_MODE_DISABLED &&
4579
2/2
✓ Branch 0 taken 19929 times.
✓ Branch 1 taken 17075 times.
37004 (mysql->server_capabilities & CLIENT_SSL)) {
4580 /* Do the SSL layering. */
4581 19929 struct st_mysql_options *options = &mysql->options;
4582 struct st_VioSSLFd *ssl_fd;
4583 19929 enum enum_ssl_init_error ssl_init_error = SSL_INITERR_NOERROR;
4584 const char *cert_error;
4585 unsigned long ssl_error;
4586 char buff[33], *end;
4587 19929 const bool verify_identity =
4588 19929 mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT;
4589
4590 /* check if server supports compression else turn off client capability */
4591
2/2
✓ Branch 0 taken 1078 times.
✓ Branch 1 taken 18851 times.
19929 if (!(mysql->server_capabilities & CLIENT_ZSTD_COMPRESSION_ALGORITHM))
4592 1078 mysql->client_flag &= ~CLIENT_ZSTD_COMPRESSION_ALGORITHM;
4593
2/2
✓ Branch 0 taken 1078 times.
✓ Branch 1 taken 18851 times.
19929 if (!(mysql->server_capabilities & CLIENT_COMPRESS))
4594 1078 mysql->client_flag &= ~CLIENT_COMPRESS;
4595
4596 19929 end = mysql_fill_packet_header(mysql, buff, sizeof(buff));
4597
4598 /*
4599 Send mysql->client_flag, max_packet_size - unencrypted otherwise
4600 the server does not know we want to do SSL
4601 */
4602
2/8
✓ Branch 0 taken 16892 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 16892 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
16892 MYSQL_TRACE(SEND_SSL_REQUEST, mysql,
4603 ((size_t)(end - buff), (const unsigned char *)buff));
4604
3/6
✓ Branch 0 taken 19930 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19930 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 19930 times.
39857 if (my_net_write(net, (uchar *)buff, (size_t)(end - buff)) ||
4605
2/4
✓ Branch 0 taken 19930 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 19930 times.
19930 net_flush(net)) {
4606 set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
4607 ER_CLIENT(CR_SERVER_LOST_EXTENDED),
4608 "sending connection information to server",
4609 errno);
4610 89 goto error;
4611 }
4612
4613
2/10
✓ Branch 0 taken 16892 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 16892 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
16892 MYSQL_TRACE_STAGE(mysql, SSL_NEGOTIATION);
4614
4615 /* Create the VioSSLConnectorFd - init SSL and load certs */
4616
4/4
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 19894 times.
✓ Branch 2 taken 47 times.
✓ Branch 3 taken 19880 times.
39857 if (!(ssl_fd = new_VioSSLConnectorFd(
4617 19930 options->ssl_key, options->ssl_cert, options->ssl_ca,
4618
1/2
✓ Branch 0 taken 19927 times.
✗ Branch 1 not taken.
19930 options->ssl_capath, options->ssl_cipher,
4619
1/2
✓ Branch 0 taken 19930 times.
✗ Branch 1 not taken.
19930 options->extension ? options->extension->tls_ciphersuites
4620 : nullptr,
4621 &ssl_init_error,
4622
1/2
✓ Branch 0 taken 19930 times.
✗ Branch 1 not taken.
19930 options->extension ? options->extension->ssl_crl : nullptr,
4623
1/2
✓ Branch 0 taken 19930 times.
✗ Branch 1 not taken.
19930 options->extension ? options->extension->ssl_crlpath : nullptr,
4624
1/2
✓ Branch 0 taken 19930 times.
✗ Branch 1 not taken.
19930 options->extension ? options->extension->ssl_ctx_flags : 0,
4625 verify_identity ? mysql->host : nullptr))) {
4626
2/4
✓ Branch 0 taken 47 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 47 times.
✗ Branch 3 not taken.
47 set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
4627 ER_CLIENT(CR_SSL_CONNECTION_ERROR),
4628 sslGetErrString(ssl_init_error));
4629 47 goto error;
4630 }
4631 19880 mysql->connector_fd = (unsigned char *)ssl_fd;
4632
1/2
✓ Branch 0 taken 19880 times.
✗ Branch 1 not taken.
19880 SSL_SESSION *ssl_session = ssl_session_deserialize_from_data(mysql);
4633
4634 /* Connect to the server */
4635
3/8
✓ Branch 0 taken 19881 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19882 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 19882 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
19880 DBUG_PRINT("info", ("IO layer change in progress..."));
4636
2/8
✓ Branch 0 taken 16846 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 16846 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
16846 MYSQL_TRACE(SSL_CONNECT, mysql, ());
4637
3/4
✓ Branch 0 taken 19882 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 42 times.
✓ Branch 3 taken 19840 times.
19882 if (sslconnect(ssl_fd, net->vio, (long)(mysql->options.connect_timeout),
4638 ssl_session, &ssl_error, nullptr)) {
4639 char buf[512];
4640
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 ERR_error_string_n(ssl_error, buf, 512);
4641 42 buf[511] = 0;
4642
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
4643 ER_CLIENT(CR_SSL_CONNECTION_ERROR), buf);
4644
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
42 if (ssl_session != nullptr) SSL_SESSION_free(ssl_session);
4645 42 goto error;
4646 }
4647
3/4
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 19798 times.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
19840 if (ssl_session != nullptr) SSL_SESSION_free(ssl_session);
4648
3/8
✓ Branch 0 taken 19840 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19841 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 19841 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
19840 DBUG_PRINT("info", ("IO layer change done!"));
4649
4650 /* Verify server cert */
4651
3/4
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 19819 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 19841 times.
19863 if (verify_identity &&
4652
2/4
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
22 ssl_verify_server_cert(net->vio, mysql->host, &cert_error)) {
4653 set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
4654 ER_CLIENT(CR_SSL_CONNECTION_ERROR), cert_error);
4655 goto error;
4656 }
4657
4658
2/8
✓ Branch 0 taken 16824 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 16824 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
16824 MYSQL_TRACE(SSL_CONNECTED, mysql, ());
4659
2/10
✓ Branch 0 taken 16824 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 16824 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
16824 MYSQL_TRACE_STAGE(mysql, AUTHENTICATE);
4660 }
4661
4662 382720 return 0;
4663
4664 132 error:
4665 132 return 1;
4666 }
4667
4668 /**
4669 This function will establish asynchronous ssl connection by completing 4
4670 different ssl connection states. Initial state is set to SSL_NONE during
4671 which this functions does priliminary checks like if server supports ssl
4672 or not, if CA certificate is required etc. Once preliminary checks are
4673 done state is changed to SSL_REQUEST. In this state ssl request packet
4674 is sent by client. If this network IO is complete, state is changed to
4675 SSL_CONNECT. During SSL_CONNECT sslconnect() is called which can return
4676 immediately or complete SSL handshake. If it returns immediately client
4677 will save all SSL context in struct mysql_async_auth, so that next call
4678 to this function will ensure that SSL_new() is not called twice. Once
4679 ssl connection is established state is changed to SSL_COMPLETE.
4680
4681 @param[in] mysql Client connection handle.
4682 @param[out] res set to false in case of success and true for
4683 error.
4684
4685 @retval NET_ASYNC_NOT_READY ssl connection not yet established
4686 @retval NET_ASYNC_COMPLETE ssl connection established
4687 */
4688 17438 static net_async_status cli_establish_ssl_nonblocking(MYSQL *mysql, int *res) {
4689
1/2
✓ Branch 0 taken 17438 times.
✗ Branch 1 not taken.
17438 DBUG_TRACE;
4690 17438 NET *net = &mysql->net;
4691
1/2
✓ Branch 0 taken 17438 times.
✗ Branch 1 not taken.
17438 NET_ASYNC *net_async = NET_ASYNC_DATA(net);
4692
2/6
✓ Branch 0 taken 17438 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17438 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
17438 mysql_async_connect *ctx = ASYNC_DATA(mysql)->connect_context;
4693
4694
2/2
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 17388 times.
17438 if (ctx->ssl_state == SSL_NONE) {
4695 /* Don't fallback on unencrypted connection if SSL required. */
4696
1/2
✓ Branch 0 taken 50 times.
✗ Branch 1 not taken.
50 if (mysql->options.extension &&
4697
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 17 times.
50 mysql->options.extension->ssl_mode >= SSL_MODE_REQUIRED &&
4698
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 !(mysql->server_capabilities & CLIENT_SSL)) {
4699 set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
4700 ER_CLIENT(CR_SSL_CONNECTION_ERROR),
4701 "SSL is required but the server doesn't "
4702 "support it");
4703 goto error;
4704 }
4705
4706 /*
4707 If the ssl_mode is VERIFY_CA or VERIFY_IDENTITY, make sure
4708 that the connection doesn't succeed without providing the
4709 CA certificate.
4710 */
4711
1/2
✓ Branch 0 taken 50 times.
✗ Branch 1 not taken.
50 if (mysql->options.extension &&
4712
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 mysql->options.extension->ssl_mode > SSL_MODE_REQUIRED &&
4713 !(mysql->options.ssl_ca || mysql->options.ssl_capath)) {
4714 set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
4715 ER_CLIENT(CR_SSL_CONNECTION_ERROR),
4716 "CA certificate is required if ssl-mode "
4717 "is VERIFY_CA or VERIFY_IDENTITY");
4718 goto error;
4719 }
4720
4721 /*
4722 Attempt SSL connection if ssl_mode != SSL_MODE_DISABLED and
4723 the server supports SSL. Fallback on unencrypted
4724 connection otherwise.
4725 */
4726
1/2
✓ Branch 0 taken 50 times.
✗ Branch 1 not taken.
50 if (!mysql->options.extension ||
4727
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 17 times.
50 mysql->options.extension->ssl_mode == SSL_MODE_DISABLED ||
4728
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 !(mysql->server_capabilities & CLIENT_SSL)) {
4729 17 goto done;
4730 }
4731 33 ctx->ssl_state = SSL_REQUEST;
4732 }
4733
4734
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 17388 times.
17421 if (ctx->ssl_state == SSL_REQUEST) {
4735 char buff[33], *end;
4736
4737 33 end = mysql_fill_packet_header(mysql, buff, sizeof(buff));
4738
4739 /*
4740 Send mysql->client_flag, max_packet_size - unencrypted
4741 otherwise the server does not know we want to do SSL
4742 */
4743
2/8
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 33 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
33 MYSQL_TRACE(SEND_SSL_REQUEST, mysql,
4744 ((size_t)(end - buff), (const unsigned char *)buff));
4745 bool ret;
4746
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 if (my_net_write_nonblocking(net, (uchar *)buff, (size_t)(end - buff),
4747
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 &ret) == NET_ASYNC_NOT_READY) {
4748 return NET_ASYNC_NOT_READY;
4749 }
4750
4751
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (ret) {
4752 set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
4753 ER_CLIENT(CR_SERVER_LOST_EXTENDED),
4754 "sending connection information to server",
4755 errno);
4756 goto error;
4757 }
4758
4759 33 ctx->ssl_state = SSL_CONNECT;
4760 }
4761
4762
1/2
✓ Branch 0 taken 17421 times.
✗ Branch 1 not taken.
17421 if (ctx->ssl_state == SSL_CONNECT) {
4763 /* Do the SSL layering. */
4764 17421 struct st_mysql_options *options = &mysql->options;
4765 struct st_VioSSLFd *ssl_fd;
4766 enum enum_ssl_init_error ssl_init_error;
4767 const char *cert_error;
4768 unsigned long ssl_error;
4769 size_t ret;
4770 17421 const bool verify_identity =
4771 17421 mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT;
4772
4773
2/10
✓ Branch 0 taken 17421 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 17421 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
17421 MYSQL_TRACE_STAGE(mysql, SSL_NEGOTIATION);
4774
4775
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 17388 times.
17421 if (!mysql->connector_fd) {
4776
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 long flags = options->extension ? options->extension->ssl_ctx_flags : 0;
4777
4778 /* Create the VioSSLConnectorFd - init SSL and load certs */
4779
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 33 times.
66 if (!(ssl_fd = new_VioSSLConnectorFd(
4780 33 options->ssl_key, options->ssl_cert, options->ssl_ca,
4781
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 options->ssl_capath, options->ssl_cipher,
4782
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 options->extension ? options->extension->tls_ciphersuites
4783 : nullptr,
4784 &ssl_init_error,
4785
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 options->extension ? options->extension->ssl_crl : nullptr,
4786
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 options->extension ? options->extension->ssl_crlpath : nullptr,
4787 flags, verify_identity ? mysql->host : nullptr))) {
4788 set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR,
4789 unknown_sqlstate,
4790 ER_CLIENT(CR_SSL_CONNECTION_ERROR),
4791 sslGetErrString(ssl_init_error));
4792 goto error;
4793 }
4794 33 mysql->connector_fd = (unsigned char *)ssl_fd;
4795 } else {
4796 17388 ssl_fd = (struct st_VioSSLFd *)mysql->connector_fd;
4797 }
4798
1/2
✓ Branch 0 taken 17421 times.
✗ Branch 1 not taken.
17421 SSL_SESSION *ssl_session = ssl_session_deserialize_from_data(mysql);
4799
4800 /* Connect to the server */
4801
3/8
✓ Branch 0 taken 17421 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17421 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 17421 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
17421 DBUG_PRINT("info", ("IO layer change in progress..."));
4802
2/8
✓ Branch 0 taken 17421 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 17421 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
17421 MYSQL_TRACE(SSL_CONNECT, mysql, ());
4803
2/2
✓ Branch 0 taken 17389 times.
✓ Branch 1 taken 32 times.
17421 if ((ret = sslconnect(ssl_fd, net->vio,
4804
1/2
✓ Branch 0 taken 17421 times.
✗ Branch 1 not taken.
17421 (long)(mysql->options.connect_timeout), ssl_session,
4805 &ssl_error, &ctx->ssl))) {
4806
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 17389 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
17389 if (ssl_session != nullptr) SSL_SESSION_free(ssl_session);
4807
1/3
✓ Branch 0 taken 17389 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
17389 switch (ret) {
4808 17389 case VIO_SOCKET_WANT_READ:
4809 17389 net_async->async_blocking_state = NET_NONBLOCKING_READ;
4810 17389 return NET_ASYNC_NOT_READY;
4811 case VIO_SOCKET_WANT_WRITE:
4812 net_async->async_blocking_state = NET_NONBLOCKING_WRITE;
4813 return NET_ASYNC_NOT_READY;
4814 default:
4815 break;
4816 /* continue for error handling */
4817 }
4818
4819 char buf[512];
4820 ERR_error_string_n(ssl_error, buf, 512);
4821 buf[511] = 0;
4822 set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
4823 ER_CLIENT(CR_SSL_CONNECTION_ERROR), buf);
4824 goto error;
4825 }
4826
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
32 if (ssl_session != nullptr) SSL_SESSION_free(ssl_session);
4827
3/8
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 32 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 32 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
32 DBUG_PRINT("info", ("IO layer change done!"));
4828
4829 /* sslconnect creates a new vio, so update it. */
4830
1/2
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
32 vio_set_blocking_flag(net->vio, !ctx->non_blocking);
4831
4832 /* Verify server cert */
4833
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 32 times.
32 if (verify_identity &&
4834 ssl_verify_server_cert(net->vio, mysql->host, &cert_error)) {
4835 set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
4836 ER_CLIENT(CR_SSL_CONNECTION_ERROR), cert_error);
4837 goto error;
4838 }
4839
4840
2/8
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 32 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
32 MYSQL_TRACE(SSL_CONNECTED, mysql, ());
4841
2/10
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 32 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
32 MYSQL_TRACE_STAGE(mysql, AUTHENTICATE);
4842 }
4843
4844 done:
4845 49 *res = 0;
4846 49 ctx->ssl_state = SSL_COMPLETE;
4847 49 return NET_ASYNC_COMPLETE;
4848
4849 error:
4850 *res = 1;
4851 ctx->ssl_state = SSL_COMPLETE;
4852 return NET_ASYNC_COMPLETE;
4853 17438 }
4854
4855 /**
4856 Asynchronous authentication phase is divided into several smaller chunks
4857 of subtasks like:
4858 1. Determine the default/initial plugin to use
4859 2. Call authentication plugin API
4860 3. Handle response from authentication plugin API
4861 4. Check if server asked to use a different authentication plugin
4862 5. In case server asked to use a different authentication plugin
4863 use that plugin to start the authentication process again.
4864 6. Complete authentication.
4865
4866 All above tasks are implemented in below authsm_* functions where
4867 authsm stads for authentication state machine.
4868 */
4869 static mysql_state_machine_status authsm_begin_plugin_auth(
4870 mysql_async_auth *ctx);
4871 static mysql_state_machine_status authsm_run_first_authenticate_user(
4872 mysql_async_auth *ctx);
4873 static mysql_state_machine_status authsm_handle_first_authenticate_user(
4874 mysql_async_auth *ctx);
4875 static mysql_state_machine_status authsm_read_change_user_result(
4876 mysql_async_auth *ctx);
4877 static mysql_state_machine_status authsm_handle_change_user_result(
4878 mysql_async_auth *ctx);
4879 static mysql_state_machine_status authsm_run_second_authenticate_user(
4880 mysql_async_auth *ctx);
4881 static mysql_state_machine_status authsm_handle_second_authenticate_user(
4882 mysql_async_auth *ctx);
4883 static mysql_state_machine_status authsm_finish_auth(mysql_async_auth *ctx);
4884 static mysql_state_machine_status authsm_init_multi_auth(mysql_async_auth *ctx);
4885 static mysql_state_machine_status authsm_do_multi_plugin_auth(
4886 mysql_async_auth *ctx);
4887 static mysql_state_machine_status authsm_handle_multi_auth_response(
4888 mysql_async_auth *ctx);
4889
4890 /**
4891 Asynchronous connection phase is divided into several smaller modules
4892 where wach module does following:
4893 1. Begin the connection to the server, including any DNS resolution
4894 necessary, socket configuration, etc
4895 2. Complete the connection itself
4896 3. Connection established, read the first packet
4897 4. Parse the handshake from the server
4898 5. Establish SSL connection if needed
4899 6. Invoke the plugin to send the authentication data to the server
4900 7. Authenticated, set initial database if specified
4901 8. Send COM_INIT_DB.
4902 9. Prepare to send a sequence of init commands.
4903 10.Send an init command.
4904
4905 Below are the modules which does all above tasks.
4906 */
4907 static mysql_state_machine_status csm_begin_connect(mysql_async_connect *ctx);
4908 static mysql_state_machine_status csm_complete_connect(
4909 mysql_async_connect *ctx);
4910 static mysql_state_machine_status csm_wait_connect(mysql_async_connect *ctx);
4911 static mysql_state_machine_status csm_read_greeting(mysql_async_connect *ctx);
4912 static mysql_state_machine_status csm_parse_handshake(mysql_async_connect *ctx);
4913 static mysql_state_machine_status csm_establish_ssl(mysql_async_connect *ctx);
4914 static mysql_state_machine_status csm_authenticate(mysql_async_connect *ctx);
4915 static mysql_state_machine_status csm_prep_select_database(
4916 mysql_async_connect *ctx);
4917 #ifndef MYSQL_SERVER
4918 static mysql_state_machine_status csm_prep_init_commands(
4919 mysql_async_connect *ctx);
4920 static mysql_state_machine_status csm_send_one_init_command(
4921 mysql_async_connect *ctx);
4922 #endif
4923
4924 #define MAX_CONNECTION_ATTR_STORAGE_LENGTH 65536
4925
4926 26726873 int mysql_get_socket_descriptor(MYSQL *mysql) {
4927
2/4
✓ Branch 0 taken 26726873 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26726873 times.
✗ Branch 3 not taken.
26726873 if (mysql && mysql->net.vio) {
4928 26726873 return vio_fd(mysql->net.vio);
4929 }
4930 return -1;
4931 }
4932
4933 /* clang-format off */
4934 /**
4935 @page page_protocol_connection_phase_packets_protocol_handshake_response Protocol::HandshakeResponse:
4936
4937 Depending on the servers support for the ::CLIENT_PROTOCOL_41 capability and
4938 the clients understanding of that flag the client has to send either
4939 a @ref sect_protocol_connection_phase_packets_protocol_handshake_response320 or
4940 @ref sect_protocol_connection_phase_packets_protocol_handshake_response41.
4941
4942 @sa send_client_reply_packet
4943
4944 @section sect_protocol_connection_phase_packets_protocol_handshake_response320 Protocol::HandshakeResponse320
4945
4946 Old Handshake Response Packet used by old clients or if the server doesn't
4947 support ::CLIENT_PROTOCOL_41 @ref group_cs_capabilities_flags flag.
4948
4949 <table>
4950 <caption>Payload</caption>
4951 <tr><th>Type</th><th>Name</th><th>Description</th></tr>
4952 <tr><td>@ref a_protocol_type_int2 "int&lt;2&gt;"</td>
4953 <td>client_flag</td>
4954 <td>\ref group_cs_capabilities_flags, only the lower 16 bits. ::CLIENT_PROTOCOL_41 should never be set</td></tr>
4955 <tr><td>@ref a_protocol_type_int3 "int&lt;3&gt;"</td>
4956 <td>max_packet_size</td>
4957 <td>maximum packet size, 0xFFFFFF max</td></tr>
4958 <tr><td>@ref sect_protocol_basic_dt_string_null "string&lt;NUL&gt;"</td>
4959 <td>username</td>
4960 <td>login user name</td></tr>
4961 <tr><td colspan="3">if capabilities @& ::CLIENT_CONNECT_WITH_DB {</td></tr>
4962 <tr><td>@ref sect_protocol_basic_dt_string_null "string&lt;NUL&gt;"</td>
4963 <td>auth-response</td>
4964 <td>Opaque authentication response data generated by
4965 Authentication Method indicated by the plugin name field.</td></tr>
4966 <tr><td>@ref sect_protocol_basic_dt_string_null "string&lt;NUL&gt;"</td>
4967 <td>database</td>
4968 <td>initial database for the connection.
4969 This string should be interpreted using the character set indicated by
4970 character set field.</td></tr>
4971 <tr><td colspan="3">} else {</td></tr>
4972 <tr><td>@ref sect_protocol_basic_dt_string_eof "string&lt;EOF&gt;"</td>
4973 <td>auth-response</td>
4974 <td>Opaque authentication response data generated by
4975 Authentication Method indicated by the plugin name field.</td></tr>
4976 <tr><td colspan="3">}</td></tr>
4977 </table>
4978
4979 Example
4980 ========
4981
4982 ~~~~~~~~~~~~~~~~~~~~~
4983 11 00 00 01 85 24 00 00 00 6f 6c 64 00 47 44 53 .....$...old.GDS
4984 43 51 59 52 5f CQYR_
4985 ~~~~~~~~~~~~~~~~~~~~~
4986
4987 @note If auth-response is followed by a database field it must be
4988 NULL terminated.
4989
4990 @section sect_protocol_connection_phase_packets_protocol_handshake_response41 Protocol::HandshakeResponse41
4991
4992 Handshake Response Packet sent by 4.1+ clients supporting
4993 ::CLIENT_PROTOCOL_41 @ref group_cs_capabilities_flags flag,
4994 if the server announced it in its
4995 @ref page_protocol_connection_phase_packets_protocol_handshake.
4996 Otherwise (talking to an old server) the
4997 @ref sect_protocol_connection_phase_packets_protocol_handshake_response320
4998 packet must be used.
4999
5000
5001 <table>
5002 <caption>Payload</caption>
5003 <tr><th>Type</th><th>Name</th><th>Description</th></tr>
5004 <tr><td>@ref a_protocol_type_int4 "int&lt;4&gt;"</td>
5005 <td>client_flag</td>
5006 <td>\ref group_cs_capabilities_flags, ::CLIENT_PROTOCOL_41 always set.</td></tr>
5007 <tr><td>@ref a_protocol_type_int4 "int&lt;4&gt;"</td>
5008 <td>max_packet_size</td>
5009 <td>maximum packet size</td></tr>
5010 <tr><td>@ref a_protocol_type_int1 "int&lt;1&gt;"</td>
5011 <td>character_set</td>
5012 <td>client charset \ref a_protocol_character_set, only the lower 8-bits</td></tr>
5013 <tr><td>@ref sect_protocol_basic_dt_string_fix "string[23]"</td>
5014 <td>filler</td>
5015 <td>filler to the size of the handhshake response packet. All 0s.</td></tr>
5016 <tr><td>@ref sect_protocol_basic_dt_string_null "string&lt;NUL&gt;"</td>
5017 <td>username</td>
5018 <td>login user name</td></tr>
5019 <tr><td colspan="3">if capabilities @& ::CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA {</td></tr>
5020 <tr><td>@ref sect_protocol_basic_dt_string_le "string&lt;length&gt;"</td>
5021 <td>auth_response</td>
5022 <td>opaque authentication response data generated by
5023 Authentication Method indicated by the plugin name field. </td></tr>
5024 <tr><td colspan="3">} else {</td></tr>
5025 <tr><td>@ref a_protocol_type_int1 "int&lt;1&gt;"</td>
5026 <td>auth_response_length</td>
5027 <td>length of auth_response</td></tr>
5028 <tr><td>@ref sect_protocol_basic_dt_string_le "string&lt;length&gt;"</td>
5029 <td>auth_response</td>
5030 <td>opaque authentication response data generated by
5031 Authentication Method indicated by the plugin name field. </td></tr>
5032 <tr><td colspan="3">}</td></tr>
5033 <tr><td colspan="3">if capabilities @& ::CLIENT_CONNECT_WITH_DB {</td></tr>
5034 <tr><td>@ref sect_protocol_basic_dt_string_null "string&lt;NUL&gt;"</td>
5035 <td>database</td>
5036 <td>initial database for the connection.
5037 This string should be interpreted using the character set indicated by
5038 character set field.</td></tr>
5039 <tr><td colspan="3">}</td></tr>
5040 <tr><td colspan="3">if capabilities @& ::CLIENT_PLUGIN_AUTH {</td></tr>
5041 <tr><td>@ref sect_protocol_basic_dt_string_null "string&lt;NUL&gt;"</td>
5042 <td>client_plugin_name</td>
5043 <td>the Authentication Method used by the client to generate
5044 auth-response value in this packet. This is an UTF-8 string. </td></tr>
5045 <tr><td colspan="3">}</td></tr>
5046 <tr><td colspan="3">if capabilities @& ::CLIENT_CONNECT_ATTRS {</td></tr>
5047 <tr><td>@ref sect_protocol_basic_dt_int_le "int&lt;lenenc&gt;"</td>
5048 <td>length of all key-values</td>
5049 <td>affected rows</td></tr>
5050 <tr><td>@ref sect_protocol_basic_dt_string_le "string&lt;lenenc&gt;"</td>
5051 <td>key1</td>
5052 <td>Name of the 1st client attribute</td></tr>
5053 <tr><td>@ref sect_protocol_basic_dt_string_le "string&lt;lenenc&gt;"</td>
5054 <td>value1</td>
5055 <td>Value of the 1st client attribute</td></tr>
5056 <tr><td colspan="3">.. (if more data in length of all key-values, more keys and values parts)</td></tr>
5057 <tr><td colspan="3">}</td></tr>
5058 <tr><td>@ref a_protocol_type_int1 "int&lt;1&gt;"</td>
5059 <td>zstd_compression_level</td>
5060 <td>compression level for zstd compression algorithm</td></tr>
5061 </table>
5062
5063 Example
5064 ========
5065
5066 On MySQL 5.5.8 with ::CLIENT_PROTOCOL_41 ::CLIENT_PLUGIN_AUTH, CLIENT_SECURE_CONNECTION (removed in 8.0),
5067 and ::CLIENT_CONNECT_WITH_DB set, it may look like:
5068
5069 ~~~~~~~~~~~~~~~~~~~~~
5070 54 00 00 01 8d a6 0f 00 00 00 00 01 08 00 00 00 T...............
5071 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5072 00 00 00 00 70 61 6d 00 14 ab 09 ee f6 bc b1 32 ....pam........2
5073 3e 61 14 38 65 c0 99 1d 95 7d 75 d4 47 74 65 73 >a.8e....}u.Gtes
5074 74 00 6d 79 73 71 6c 5f 6e 61 74 69 76 65 5f 70 t.mysql_native_p
5075 61 73 73 77 6f 72 64 00 assword.
5076 ~~~~~~~~~~~~~~~~~~~~~
5077
5078 Starting with MySQL 5.6.6 the client may send attributes
5079 if ::CLIENT_CONNECT_ATTRS is set:
5080
5081 ~~~~~~~~~~~~~~~~~~~~~
5082 b2 00 00 01 85 a2 1e 00 00 00 00 40 08 00 00 00 ...........@....
5083 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5084 00 00 00 00 72 6f 6f 74 00 14 22 50 79 a2 12 d4 ....root.."Py...
5085 e8 82 e5 b3 f4 1a 97 75 6b c8 be db 9f 80 6d 79 .......uk.....my
5086 73 71 6c 5f 6e 61 74 69 76 65 5f 70 61 73 73 77 sql_native_passw
5087 6f 72 64 00 61 03 5f 6f 73 09 64 65 62 69 61 6e ord.a._os.debian
5088 36 2e 30 0c 5f 63 6c 69 65 6e 74 5f 6e 61 6d 65 6.0._client_name
5089 08 6c 69 62 6d 79 73 71 6c 04 5f 70 69 64 05 32 .libmysql._pid.2
5090 32 33 34 34 0f 5f 63 6c 69 65 6e 74 5f 76 65 72 2344._client_ver
5091 73 69 6f 6e 08 35 2e 36 2e 36 2d 6d 39 09 5f 70 sion.5.6.6-m9._p
5092 6c 61 74 66 6f 72 6d 06 78 38 36 5f 36 34 03 66 latform.x86_64.f
5093 6f 6f 03 62 61 72 oo.bar
5094 ~~~~~~~~~~~~~~~~~~~~~
5095
5096 @warning Currently, multibyte character sets such as UCS2, UTF16 and
5097 UTF32 are not supported.
5098
5099 @note If client wants to have a secure SSL connection and sets
5100 CLIENT_SSL flag it should first send the
5101 @ref page_protocol_connection_phase_packets_protocol_ssl_request packet
5102 and only then, after establishing the secure connection, it should send
5103 the @ref page_protocol_connection_phase_packets_protocol_handshake_response
5104 packet.
5105 */
5106 /* clang-format on */
5107
5108 /**
5109 sends a client authentication packet (second packet in the 3-way handshake)
5110
5111 @param mpvio The connection to use
5112 @param data The scramble to send
5113 @param data_len Length of data
5114 @param buff_out Buffer holding client handshake packet
5115 @param buff_len Length of buffer holding client handshake packet
5116 @retval 0 ok
5117 @retval 1 error
5118
5119 @sa mysql_fill_packet_header()
5120 page_protocol_conn_packets_protocol_handshake_response
5121 */
5122 382760 static bool prep_client_reply_packet(MCPVIO_EXT *mpvio, const uchar *data,
5123 int data_len, char **buff_out,
5124 int *buff_len) {
5125
1/2
✓ Branch 0 taken 382895 times.
✗ Branch 1 not taken.
382760 DBUG_TRACE;
5126 382895 MYSQL *mysql = mpvio->mysql;
5127 // Simulate mismatching ssl_charset_code number in handshake response
5128 // In order to have different, but valid number using my_charset_* objects
5129
4/6
✓ Branch 0 taken 382890 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 382889 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
382895 DBUG_EXECUTE_IF("simulate_bad_ssl_charset_code", {
5130 if (mysql->charset->number != my_charset_bin.number)
5131 mysql->charset->number = my_charset_bin.number;
5132 else
5133 mysql->charset->number = my_charset_latin1.number;
5134 });
5135 char *buff, *end;
5136 size_t buff_size;
5137 382890 size_t connect_attrs_len =
5138 765779 (mysql->server_capabilities & CLIENT_CONNECT_ATTRS &&
5139
2/2
✓ Branch 0 taken 382882 times.
✓ Branch 1 taken 7 times.
382889 mysql->options.extension)
5140
2/2
✓ Branch 0 taken 382889 times.
✓ Branch 1 taken 1 times.
765779 ? mysql->options.extension->connection_attributes_length
5141 : 0;
5142 382890 unsigned int compress_level = 0;
5143 382890 bool server_zstd =
5144 382890 (mysql->server_capabilities & CLIENT_ZSTD_COMPRESSION_ALGORITHM);
5145 382890 bool client_zstd =
5146 382890 (mysql->options.client_flag & CLIENT_ZSTD_COMPRESSION_ALGORITHM);
5147
5148 /* validate compression configuration */
5149
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 382890 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
382890 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
5150
2/2
✓ Branch 0 taken 8287 times.
✓ Branch 1 taken 374603 times.
382890 if (mysql->options.extension->compression_algorithm) {
5151
1/2
✓ Branch 0 taken 8287 times.
✗ Branch 1 not taken.
8287 std::string algorithm = mysql->options.extension->compression_algorithm;
5152
1/2
✓ Branch 0 taken 8287 times.
✗ Branch 1 not taken.
16574 if (!algorithm.empty() &&
5153
8/16
✓ Branch 0 taken 8287 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8287 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 8285 times.
✓ Branch 6 taken 8287 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 8287 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✓ Branch 11 taken 8285 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
16574 validate_compression_attributes(algorithm, std::string(), true)) {
5154
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 set_mysql_error(mysql, CR_COMPRESSION_WRONGLY_CONFIGURED,
5155 unknown_sqlstate);
5156 2 return true;
5157 }
5158
2/2
✓ Branch 0 taken 8285 times.
✓ Branch 1 taken 2 times.
8287 }
5159
5160 /**
5161 If server/client is configured to use zstd compression then set compression
5162 level if specified, else set level to a default value.
5163 */
5164
4/4
✓ Branch 0 taken 364402 times.
✓ Branch 1 taken 18486 times.
✓ Branch 2 taken 108 times.
✓ Branch 3 taken 364294 times.
382888 if (server_zstd && client_zstd) {
5165
1/2
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
108 if (mysql->options.extension &&
5166
2/2
✓ Branch 0 taken 105 times.
✓ Branch 1 taken 3 times.
108 mysql->options.extension->zstd_compression_level)
5167 105 compress_level = mysql->options.extension->zstd_compression_level;
5168 else
5169 3 compress_level = default_zstd_compression_level;
5170 }
5171 /* Remove those compression capabilities that server does not support. */
5172
2/2
✓ Branch 0 taken 18378 times.
✓ Branch 1 taken 364510 times.
382888 if (!(mysql->server_capabilities & CLIENT_COMPRESS))
5173 18378 mysql->client_flag &= ~CLIENT_COMPRESS;
5174
2/2
✓ Branch 0 taken 18362 times.
✓ Branch 1 taken 364526 times.
382888 if (!(mysql->server_capabilities & CLIENT_ZSTD_COMPRESSION_ALGORITHM))
5175 18362 mysql->client_flag &= ~CLIENT_ZSTD_COMPRESSION_ALGORITHM;
5176 /*
5177 If server and client have no compression algorithms in common, we must
5178 fall back to uncompressed. In that case, check that uncompressed is
5179 allowed by client.
5180 */
5181
2/2
✓ Branch 0 taken 382664 times.
✓ Branch 1 taken 224 times.
382888 if (!(mysql->client_flag & CLIENT_COMPRESS) &&
5182
2/2
✓ Branch 0 taken 382577 times.
✓ Branch 1 taken 87 times.
382664 !(mysql->client_flag & CLIENT_ZSTD_COMPRESSION_ALGORITHM) &&
5183
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 382517 times.
382577 mysql->options.extension->connection_compressed) {
5184
1/2
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
60 set_mysql_error(mysql, CR_COMPRESSION_WRONGLY_CONFIGURED, unknown_sqlstate);
5185 60 return true;
5186 }
5187
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 382828 times.
382828 assert(connect_attrs_len < MAX_CONNECTION_ATTR_STORAGE_LENGTH);
5188
5189 382828 *buff_out = nullptr;
5190 382828 *buff_len = 0;
5191
5192 /*
5193 Fixed size of the packet is 32 bytes. See mysql_fill_packet_header.
5194 +9 because data is a length encoded binary where meta data size is max 9.
5195 */
5196 765656 buff_size = 33 + USERNAME_LENGTH + data_len + 9 + NAME_LEN + NAME_LEN +
5197
4/4
✓ Branch 0 taken 364395 times.
✓ Branch 1 taken 18433 times.
✓ Branch 2 taken 108 times.
✓ Branch 3 taken 364287 times.
382828 connect_attrs_len + 9 + ((server_zstd && client_zstd) ? 1 : 0);
5198
5199 buff = static_cast<char *>(
5200
1/2
✓ Branch 0 taken 382815 times.
✗ Branch 1 not taken.
382828 my_malloc(PSI_NOT_INSTRUMENTED, buff_size, MYF(MY_WME | MY_ZEROFILL)));
5201
5202 /* The client_flags is already calculated. Just fill in the packet header */
5203 382815 end = mysql_fill_packet_header(mysql, buff, buff_size);
5204
5205
3/8
✓ Branch 0 taken 382779 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 382802 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 382802 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
382739 DBUG_PRINT(
5206 "info",
5207 ("Server version = '%s' capabilites: %lu status: %u client_flag: %lu",
5208 mysql->server_version, mysql->server_capabilities, mysql->server_status,
5209 mysql->client_flag));
5210
5211 static_assert(MYSQL_USERNAME_LENGTH == USERNAME_LENGTH, "");
5212
5213 /* This needs to be changed as it's not useful with big packets */
5214
2/2
✓ Branch 0 taken 382769 times.
✓ Branch 1 taken 20 times.
382789 if (mysql->user[0])
5215
1/2
✓ Branch 0 taken 382752 times.
✗ Branch 1 not taken.
382769 strmake(end, mysql->user, USERNAME_LENGTH);
5216 else {
5217 #if defined(KERBEROS_LIB_CONFIGURED)
5218 /*
5219 Kerberos user name should have already read inside LDAP SASL client
5220 plugin. If it is still empty we should return error.
5221 */
5222
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (strcmp(mpvio->plugin->name, "authentication_ldap_sasl_client") == 0) {
5223 if (!mysql->user[0]) {
5224 set_mysql_error(mysql, CR_KERBEROS_USER_NOT_FOUND, unknown_sqlstate);
5225 return true;
5226 }
5227 } else
5228 #endif
5229
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 read_user_name(end);
5230 }
5231
5232 /* We have to handle different version of handshake here */
5233
3/8
✓ Branch 0 taken 382783 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 382794 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 382794 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
382772 DBUG_PRINT("info", ("user: %s", end));
5234 382794 end = strend(end) + 1;
5235
2/2
✓ Branch 0 taken 381008 times.
✓ Branch 1 taken 1792 times.
382800 if (data_len) {
5236 /*
5237 Since the older versions of server do not have
5238 CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA capability,
5239 a check is performed on this before sending auth data.
5240 If lenenc support is not available, the data is sent
5241 in the format of first byte representing the length of
5242 the string followed by the actual string.
5243 */
5244
1/2
✓ Branch 0 taken 381008 times.
✗ Branch 1 not taken.
381008 if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA)
5245 380926 end = write_length_encoded_string4(end, (char *)(buff + buff_size), data,
5246
1/2
✓ Branch 0 taken 380926 times.
✗ Branch 1 not taken.
381008 data + data_len);
5247 else
5248 end =
5249 write_string(end, (char *)(buff + buff_size), data, data + data_len);
5250
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 380926 times.
380926 if (end == nullptr) goto error;
5251 } else
5252 1792 *end++ = 0;
5253
5254 /* Add database if needed */
5255
3/4
✓ Branch 0 taken 286926 times.
✓ Branch 1 taken 95792 times.
✓ Branch 2 taken 286934 times.
✗ Branch 3 not taken.
382718 if (mpvio->db && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB)) {
5256
1/2
✓ Branch 0 taken 287016 times.
✗ Branch 1 not taken.
286934 end = strmake(end, mpvio->db, NAME_LEN) + 1;
5257
1/2
✓ Branch 0 taken 287019 times.
✗ Branch 1 not taken.
287016 mysql->db = my_strdup(key_memory_MYSQL, mpvio->db, MYF(MY_WME));
5258 }
5259
5260
1/2
✓ Branch 0 taken 382823 times.
✗ Branch 1 not taken.
382803 if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH)
5261
1/2
✓ Branch 0 taken 382831 times.
✗ Branch 1 not taken.
382823 end = strmake(end, mpvio->plugin->name, NAME_LEN) + 1;
5262
5263
1/2
✓ Branch 0 taken 382824 times.
✗ Branch 1 not taken.
382811 end = (char *)send_client_connect_attrs(mysql, (uchar *)end);
5264
5265
4/4
✓ Branch 0 taken 364486 times.
✓ Branch 1 taken 18338 times.
✓ Branch 2 taken 108 times.
✓ Branch 3 taken 364378 times.
382824 if (server_zstd && client_zstd) {
5266 /* send compression level if both client and server support it */
5267 108 *end = static_cast<unsigned char>(compress_level);
5268 108 end++;
5269 }
5270
5271 382824 *buff_out = buff;
5272 382824 *buff_len = end - buff;
5273
5274 382824 return false;
5275
5276 error:
5277 my_free(buff);
5278 return true;
5279 382886 }
5280
5281 382658 static int send_client_reply_packet(MCPVIO_EXT *mpvio, const uchar *data,
5282 int data_len) {
5283
1/2
✓ Branch 0 taken 382848 times.
✗ Branch 1 not taken.
382658 DBUG_TRACE;
5284 382848 MYSQL *mysql = mpvio->mysql;
5285 382848 NET *net = &mysql->net;
5286 382848 char *buff = nullptr, *end = nullptr;
5287 int buff_len;
5288 382848 int ret = 0;
5289 bool prep_err;
5290
5291
1/2
✓ Branch 0 taken 382845 times.
✗ Branch 1 not taken.
382848 prep_err = prep_client_reply_packet(mpvio, data, data_len, &buff, &buff_len);
5292
2/2
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 382783 times.
382845 if (prep_err) {
5293 62 return 1;
5294 }
5295
5296 382783 end = buff + buff_len;
5297 /* Write authentication package */
5298
3/8
✓ Branch 0 taken 371337 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 371334 times.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
371335 MYSQL_TRACE(SEND_AUTH_RESPONSE, mysql,
5299 ((size_t)(end - buff), (const unsigned char *)buff));
5300
4/6
✓ Branch 0 taken 382785 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 382785 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 382711 times.
765496 if (my_net_write(net, (uchar *)buff, (size_t)(end - buff)) ||
5301
2/4
✓ Branch 0 taken 382714 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 382783 times.
382785 net_flush(net)) {
5302
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
5303 ER_CLIENT(CR_SERVER_LOST_EXTENDED),
5304 3 "sending authentication information", errno);
5305 3 ret = 1;
5306 }
5307
3/8
✓ Branch 0 taken 371339 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 371309 times.
✓ Branch 5 taken 30 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
371266 MYSQL_TRACE(PACKET_SENT, mysql, ((size_t)(end - buff)));
5308
1/2
✓ Branch 0 taken 382775 times.
✗ Branch 1 not taken.
382757 my_free(buff);
5309 382775 return ret;
5310 382837 }
5311
5312 46 static net_async_status send_client_reply_packet_nonblocking(MCPVIO_EXT *mpvio,
5313 const uchar *pkt,
5314 int pkt_len,
5315 bool *result) {
5316
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 DBUG_TRACE;
5317 46 MYSQL *mysql = mpvio->mysql;
5318
2/6
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 46 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
46 mysql_async_auth *ctx = ASYNC_DATA(mysql)->connect_context->auth_context;
5319 net_async_status status;
5320
5321 46 bool error = false;
5322
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 if (!ctx->change_user_buff) {
5323 46 error =
5324
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 prep_client_reply_packet(mpvio, pkt, pkt_len, &ctx->change_user_buff,
5325 &ctx->change_user_buff_len);
5326
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 if (error) {
5327 goto end;
5328 }
5329 }
5330
5331 92 status = my_net_write_nonblocking(&mysql->net, (uchar *)ctx->change_user_buff,
5332
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 ctx->change_user_buff_len, &error);
5333
5334
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 if (status == NET_ASYNC_NOT_READY) {
5335 return NET_ASYNC_NOT_READY;
5336 }
5337
5338 46 end:
5339 46 *result = error;
5340
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 my_free(ctx->change_user_buff);
5341 46 ctx->change_user_buff = nullptr;
5342
5343 46 return NET_ASYNC_COMPLETE;
5344 46 }
5345
5346 #ifdef __clang__
5347 // Clang UBSAN false positive?
5348 // Call to function through pointer to incorrect function type
5349 static int client_mpvio_read_packet(MYSQL_PLUGIN_VIO *mpv,
5350 uchar **buf) SUPPRESS_UBSAN;
5351 #endif // __clang__
5352
5353 /**
5354 vio->read_packet() callback method for client authentication plugins
5355
5356 This function is called by a client authentication plugin, when it wants
5357 to read data from the server.
5358 */
5359 400527 static int client_mpvio_read_packet(MYSQL_PLUGIN_VIO *mpv, uchar **buf) {
5360 400527 MCPVIO_EXT *mpvio = (MCPVIO_EXT *)mpv;
5361 400527 MYSQL *mysql = mpvio->mysql;
5362 ulong pkt_len;
5363
5364 /* there are cached data left, feed it to a plugin */
5365
2/2
✓ Branch 0 taken 385909 times.
✓ Branch 1 taken 14618 times.
400527 if (mpvio->cached_server_reply.pkt_received) {
5366 385909 *buf = mpvio->cached_server_reply.pkt;
5367 385909 mpvio->cached_server_reply.pkt = nullptr;
5368 385909 mpvio->packets_read++;
5369 385909 pkt_len = mpvio->cached_server_reply.pkt_len;
5370 385909 mpvio->cached_server_reply.pkt_len = 0;
5371 385909 mpvio->cached_server_reply.pkt_received = false;
5372 385909 return pkt_len;
5373 }
5374
5375
2/2
✓ Branch 0 taken 431 times.
✓ Branch 1 taken 14187 times.
14618 if (mpvio->packets_read == 0) {
5376 /*
5377 the server handshake packet came from the wrong plugin,
5378 or it's mysql_change_user(). Either way, there is no data
5379 for a plugin to read. send a dummy packet to the server
5380 to initiate a dialog.
5381 */
5382
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 431 times.
431 if (client_mpvio_write_packet(mpv, nullptr, 0)) return (int)packet_error;
5383 }
5384
5385 /* otherwise read the data */
5386 14618 pkt_len = (*mysql->methods->read_change_user_result)(mysql);
5387
5388 /* error while reading the change user request */
5389
2/2
✓ Branch 0 taken 93 times.
✓ Branch 1 taken 14580 times.
14673 if (pkt_len == packet_error) return (int)packet_error;
5390
5391 14580 mpvio->last_read_packet_len = pkt_len;
5392 14580 *buf = mysql->net.read_pos;
5393
5394 /* was it a request to change plugins ? */
5395
2/2
✓ Branch 0 taken 1248 times.
✓ Branch 1 taken 13332 times.
14580 if (**buf == 254)
5396 1248 return (int)packet_error; /* if yes, this plugin shan't continue */
5397
5398 /*
5399 the server sends \1\255 or \1\254 instead of just \255 or \254 -
5400 for us to not confuse it with an error or "change plugin" packets.
5401 We remove this escaping \1 here.
5402
5403 See also server_mpvio_write_packet() where the escaping is done.
5404 */
5405
2/4
✓ Branch 0 taken 13332 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13332 times.
✗ Branch 3 not taken.
13332 if (pkt_len && **buf == 1) {
5406 13332 (*buf)++;
5407 13332 pkt_len--;
5408 }
5409 13332 mpvio->packets_read++;
5410 13332 return pkt_len;
5411 }
5412
5413 /**
5414 vio->read_packet() nonblocking callback method for client authentication
5415 plugins
5416 */
5417 1038 static net_async_status client_mpvio_read_packet_nonblocking(
5418 struct MYSQL_PLUGIN_VIO *mpv, uchar **buf, int *result) {
5419
1/2
✓ Branch 0 taken 1038 times.
✗ Branch 1 not taken.
1038 DBUG_TRACE;
5420 1038 MCPVIO_EXT *mpvio = (MCPVIO_EXT *)mpv;
5421 1038 MYSQL *mysql = mpvio->mysql;
5422 ulong pkt_len;
5423 int error;
5424
5425 /* there are cached data left, feed it to a plugin */
5426
2/2
✓ Branch 0 taken 49 times.
✓ Branch 1 taken 989 times.
1038 if (mpvio->cached_server_reply.pkt_received) {
5427 49 *buf = mpvio->cached_server_reply.pkt;
5428 49 mpvio->cached_server_reply.pkt = nullptr;
5429 49 mpvio->packets_read++;
5430 49 *result = mpvio->cached_server_reply.pkt_len;
5431 49 mpvio->cached_server_reply.pkt_len = 0;
5432 49 mpvio->cached_server_reply.pkt_received = false;
5433 49 return NET_ASYNC_COMPLETE;
5434 }
5435
5436
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 989 times.
989 if (mpvio->packets_read == 0) {
5437 /*
5438 the server handshake packet came from the wrong plugin,
5439 or it's mysql_change_user(). Either way, there is no data
5440 for a plugin to read. send a dummy packet to the server
5441 to initiate a dialog.
5442 */
5443 net_async_status status =
5444 client_mpvio_write_packet_nonblocking(mpv, nullptr, 0, &error);
5445 if (status == NET_ASYNC_NOT_READY) {
5446 return NET_ASYNC_NOT_READY;
5447 }
5448 if (error) {
5449 *result = (int)packet_error;
5450 return NET_ASYNC_COMPLETE;
5451 }
5452 }
5453
5454 /*
5455 packets_read needs to be set here to avoid entering above condition
5456 again.
5457 */
5458 989 mpvio->packets_read++;
5459 /* otherwise read the data */
5460 net_async_status status =
5461
1/2
✓ Branch 0 taken 989 times.
✗ Branch 1 not taken.
989 mysql->methods->read_change_user_result_nonblocking(mysql, &pkt_len);
5462
2/2
✓ Branch 0 taken 966 times.
✓ Branch 1 taken 23 times.
989 if (status == NET_ASYNC_NOT_READY) {
5463 966 return NET_ASYNC_NOT_READY;
5464 }
5465
5466 23 mpvio->last_read_packet_len = pkt_len;
5467 23 *buf = mysql->net.read_pos;
5468
5469 /* was it a request to change plugins ? */
5470
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
23 if (**buf == 254) {
5471 *result = (int)packet_error;
5472 return NET_ASYNC_COMPLETE;
5473 }
5474
5475 /*
5476 the server sends \1\255 or \1\254 instead of just \255 or \254 -
5477 for us to not confuse it with an error or "change plugin" packets.
5478 We remove this escaping \1 here.
5479 See also server_mpvio_write_packet() where the escaping is
5480 done.
5481 */
5482
2/4
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
23 if (pkt_len && **buf == 1) {
5483 23 (*buf)++;
5484 23 pkt_len--;
5485 }
5486 23 *result = pkt_len;
5487 23 return NET_ASYNC_COMPLETE;
5488 1038 }
5489
5490 #ifdef __clang__
5491 // Clang UBSAN false positive?
5492 // Call to function through pointer to incorrect function type
5493 static int client_mpvio_write_packet(MYSQL_PLUGIN_VIO *mpv, const uchar *pkt,
5494 int pkt_len) SUPPRESS_UBSAN;
5495 #endif // __clang__
5496
5497 /**
5498 vio->write_packet() callback method for client authentication plugins
5499
5500 This function is called by a client authentication plugin, when it wants
5501 to send data to the server.
5502
5503 It transparently wraps the data into a change user or authentication
5504 handshake packet, if necessary.
5505 */
5506 387645 static int client_mpvio_write_packet(MYSQL_PLUGIN_VIO *mpv, const uchar *pkt,
5507 int pkt_len) {
5508 int res;
5509 387645 MCPVIO_EXT *mpvio = (MCPVIO_EXT *)mpv;
5510
5511
2/2
✓ Branch 0 taken 383039 times.
✓ Branch 1 taken 4606 times.
387645 if (mpvio->packets_written == 0) {
5512
2/2
✓ Branch 0 taken 305 times.
✓ Branch 1 taken 382734 times.
383039 if (mpvio->mysql_change_user)
5513 305 res = send_change_user_packet(mpvio, pkt, pkt_len);
5514 else
5515 382734 res = send_client_reply_packet(mpvio, pkt, pkt_len);
5516 } else {
5517 4606 NET *net = &mpvio->mysql->net;
5518
5519
2/6
✓ Branch 0 taken 4327 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4327 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
4274 MYSQL_TRACE(SEND_AUTH_DATA, mpvio->mysql, ((size_t)pkt_len, pkt));
5520
5521
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4659 times.
4659 if (mpvio->mysql->thd)
5522 res = 1; /* no chit-chat in embedded */
5523 else
5524
2/4
✓ Branch 0 taken 4659 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4659 times.
4659 res = my_net_write(net, pkt, pkt_len) || net_flush(net);
5525
5526
2/2
✓ Branch 0 taken 4327 times.
✓ Branch 1 taken 332 times.
4659 if (!res) {
5527
2/6
✓ Branch 0 taken 4327 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4327 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
4327 MYSQL_TRACE(PACKET_SENT, mpvio->mysql, ((size_t)pkt_len));
5528 } else
5529 set_mysql_extended_error(mpvio->mysql, CR_SERVER_LOST, unknown_sqlstate,
5530 ER_CLIENT(CR_SERVER_LOST_EXTENDED),
5531 "sending authentication information", errno);
5532 }
5533 387746 mpvio->packets_written++;
5534 387746 return res;
5535 }
5536
5537 /**
5538 vio->write_packet() nonblocking callback method for client authentication
5539 plugins
5540 */
5541 60 static net_async_status client_mpvio_write_packet_nonblocking(
5542 struct MYSQL_PLUGIN_VIO *mpv, const uchar *pkt, int pkt_len, int *result) {
5543
1/2
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
60 DBUG_TRACE;
5544 60 MCPVIO_EXT *mpvio = (MCPVIO_EXT *)mpv;
5545 60 bool error = false;
5546
5547
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 14 times.
60 if (mpvio->packets_written == 0) {
5548 /* mysql_change_user_nonblocking not implemented yet. */
5549
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 assert(!mpvio->mysql_change_user);
5550 net_async_status status =
5551
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 send_client_reply_packet_nonblocking(mpvio, pkt, pkt_len, &error);
5552
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 if (status == NET_ASYNC_NOT_READY) {
5553 return NET_ASYNC_NOT_READY;
5554 }
5555 } else {
5556 14 NET *net = &mpvio->mysql->net;
5557
5558
2/8
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
14 MYSQL_TRACE(SEND_AUTH_DATA, mpvio->mysql, ((size_t)pkt_len, pkt));
5559
5560
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (mpvio->mysql->thd)
5561 *result = 1; /* no chit-chat in embedded */
5562 else {
5563 net_async_status status =
5564
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 my_net_write_nonblocking(net, pkt, pkt_len, &error);
5565
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (status == NET_ASYNC_NOT_READY) {
5566 return NET_ASYNC_NOT_READY;
5567 }
5568 14 *result = error;
5569
5570
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (error) {
5571 set_mysql_extended_error(mpvio->mysql, CR_SERVER_LOST, unknown_sqlstate,
5572 ER_CLIENT(CR_SERVER_LOST_EXTENDED),
5573 "sending authentication information", errno);
5574 } else {
5575
2/8
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
14 MYSQL_TRACE(PACKET_SENT, mpvio->mysql, ((size_t)pkt_len));
5576 }
5577 }
5578 }
5579 60 mpvio->packets_written++;
5580
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
60 *result = error ? -1 : 0;
5581 60 return NET_ASYNC_COMPLETE;
5582 60 }
5583
5584 /**
5585 fills MYSQL_PLUGIN_VIO_INFO structure with the information about the
5586 connection
5587 */
5588 1 void mpvio_info(Vio *vio, MYSQL_PLUGIN_VIO_INFO *info) {
5589 1 memset(info, 0, sizeof(*info));
5590
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 switch (vio->type) {
5591 case VIO_TYPE_TCPIP:
5592 info->protocol = MYSQL_PLUGIN_VIO_INFO::MYSQL_VIO_TCP;
5593 info->socket = (int)vio_fd(vio);
5594 return;
5595 1 case VIO_TYPE_SOCKET:
5596 1 info->protocol = MYSQL_PLUGIN_VIO_INFO::MYSQL_VIO_SOCKET;
5597 1 info->socket = (int)vio_fd(vio);
5598 1 return;
5599 case VIO_TYPE_SSL: {
5600 struct sockaddr addr;
5601 socklen_t addrlen = sizeof(addr);
5602 if (getsockname(vio_fd(vio), &addr, &addrlen)) return;
5603 info->protocol = addr.sa_family == AF_UNIX
5604 ? MYSQL_PLUGIN_VIO_INFO::MYSQL_VIO_SOCKET
5605 : MYSQL_PLUGIN_VIO_INFO::MYSQL_VIO_TCP;
5606 info->socket = (int)vio_fd(vio);
5607 return;
5608 }
5609 #ifdef _WIN32
5610 case VIO_TYPE_NAMEDPIPE:
5611 info->protocol = MYSQL_PLUGIN_VIO_INFO::MYSQL_VIO_PIPE;
5612 info->handle = vio->hPipe;
5613 return;
5614 #if defined(_WIN32)
5615 case VIO_TYPE_SHARED_MEMORY:
5616 info->protocol = MYSQL_PLUGIN_VIO_INFO::MYSQL_VIO_MEMORY;
5617 info->handle = vio->handle_file_map; /* or what ? */
5618 return;
5619 #endif
5620 #endif
5621 default:
5622 assert(0);
5623 }
5624 }
5625
5626 static void client_mpvio_info(MYSQL_PLUGIN_VIO *vio,
5627 MYSQL_PLUGIN_VIO_INFO *info) {
5628 MCPVIO_EXT *mpvio = (MCPVIO_EXT *)vio;
5629 mpvio_info(mpvio->mysql->net.vio, info);
5630 }
5631
5632 bool libmysql_cleartext_plugin_enabled = false;
5633
5634 386415 static bool check_plugin_enabled(MYSQL *mysql, mysql_async_auth *ctx) {
5635
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 386399 times.
386415 if (ctx->auth_plugin == &clear_password_client_plugin &&
5636
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 (!libmysql_cleartext_plugin_enabled &&
5637
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 (!mysql->options.extension ||
5638
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 12 times.
16 !mysql->options.extension->enable_cleartext_plugin))) {
5639 4 set_mysql_extended_error(
5640 mysql, CR_AUTH_PLUGIN_CANNOT_LOAD, unknown_sqlstate,
5641 ER_CLIENT(CR_AUTH_PLUGIN_CANNOT_LOAD),
5642 clear_password_client_plugin.name, "plugin not enabled");
5643 4 return true;
5644 }
5645
3/4
✓ Branch 0 taken 49 times.
✓ Branch 1 taken 386362 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 49 times.
386411 if (ctx->non_blocking && !ctx->auth_plugin->authenticate_user_nonblocking) {
5646 set_mysql_extended_error(
5647 mysql, CR_AUTH_PLUGIN_CANNOT_LOAD, unknown_sqlstate,
5648 ER_CLIENT(CR_AUTH_PLUGIN_CANNOT_LOAD), ctx->auth_plugin->name,
5649 "plugin does not support nonblocking connect");
5650 /*
5651 We don't return true here because not all authentication plugins support
5652 non-blocking APIs.
5653 In case plugin does not have non-blocking API, we fallback to blocking
5654 API calls to further proceed with the authentication.
5655 */
5656 }
5657 386419 return false;
5658 }
5659
5660 /**
5661 Client side of the plugin driver authentication.
5662
5663 @note this is used by both the mysql_real_connect and mysql_change_user
5664
5665 @param mysql mysql
5666 @param data pointer to the plugin auth data (scramble) in the
5667 handshake packet
5668 @param data_len the length of the data
5669 @param data_plugin a plugin that data were prepared for
5670 or 0 if it's mysql_change_user()
5671 @param db initial db to use, can be 0
5672
5673 @retval 0 ok
5674 @retval 1 error
5675 */
5676 382983 int run_plugin_auth(MYSQL *mysql, char *data, uint data_len,
5677 const char *data_plugin, const char *db) {
5678
1/2
✓ Branch 0 taken 383157 times.
✗ Branch 1 not taken.
382983 DBUG_TRACE;
5679 mysql_state_machine_status status;
5680 mysql_async_auth ctx;
5681 383157 memset(&ctx, 0, sizeof(ctx));
5682
5683 383157 ctx.mysql = mysql;
5684 383157 ctx.data = data;
5685 383157 ctx.data_len = data_len;
5686 383157 ctx.data_plugin = data_plugin;
5687 383157 ctx.db = db;
5688 383157 ctx.non_blocking = false;
5689 /* set initial auth factor to be first factor */
5690 383157 ctx.current_factor_index = 0;
5691 383157 ctx.state_function = authsm_begin_plugin_auth;
5692
5693 do {
5694
1/2
✓ Branch 0 taken 2302031 times.
✗ Branch 1 not taken.
2302239 status = ctx.state_function(&ctx);
5695
3/8
✓ Branch 0 taken 2302214 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2302175 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2302175 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2302031 DBUG_PRINT("info", ("status %d", (int)status));
5696
4/4
✓ Branch 0 taken 2299523 times.
✓ Branch 1 taken 2652 times.
✓ Branch 2 taken 1919082 times.
✓ Branch 3 taken 380441 times.
2302175 } while (status != STATE_MACHINE_FAILED && status != STATE_MACHINE_DONE);
5697
5698 383154 return status == STATE_MACHINE_FAILED;
5699 383093 }
5700
5701 /**
5702 This functions drives the authentication on client side in a nonblocking
5703 way. This function will call different modules in a sequence where each
5704 module is responsible to achieve a particular part in entire authentication
5705 phase.
5706
5707 @note this is used by both the mysql_real_connect_nonblocking
5708
5709 @param mysql mysql
5710 @param data pointer to the plugin auth data (scramble) in the
5711 handshake packet
5712 @param data_len the length of the data
5713 @param data_plugin a plugin that data were prepared for
5714 or 0 if it's mysql_change_user()
5715 @param db initial db to use, can be 0
5716
5717 @retval NET_ASYNC_NOT_READY authentication not yet complete
5718 @retval NET_ASYNC_COMPLETE authentication done
5719 */
5720 12776 mysql_state_machine_status run_plugin_auth_nonblocking(MYSQL *mysql, char *data,
5721 uint data_len,
5722 const char *data_plugin,
5723 const char *db) {
5724
1/2
✓ Branch 0 taken 12776 times.
✗ Branch 1 not taken.
12776 DBUG_TRACE;
5725
2/6
✓ Branch 0 taken 12776 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12776 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
12776 mysql_async_auth *ctx = ASYNC_DATA(mysql)->connect_context->auth_context;
5726
2/2
✓ Branch 0 taken 49 times.
✓ Branch 1 taken 12727 times.
12776 if (!ctx) {
5727 ctx = static_cast<mysql_async_auth *>(
5728
1/2
✓ Branch 0 taken 49 times.
✗ Branch 1 not taken.
49 my_malloc(key_memory_MYSQL, sizeof(*ctx), MYF(MY_WME | MY_ZEROFILL)));
5729
5730 49 ctx->mysql = mysql;
5731 49 ctx->data = data;
5732 49 ctx->data_len = data_len;
5733 49 ctx->data_plugin = data_plugin;
5734 49 ctx->db = db;
5735 49 ctx->non_blocking = true;
5736 49 ctx->current_factor_index = 0;
5737 49 ctx->state_function = authsm_begin_plugin_auth;
5738
2/6
✓ Branch 0 taken 49 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 49 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
49 ASYNC_DATA(mysql)->connect_context->auth_context = ctx;
5739 }
5740
5741
1/2
✓ Branch 0 taken 12776 times.
✗ Branch 1 not taken.
12776 mysql_state_machine_status ret = ctx->state_function(ctx);
5742
4/4
✓ Branch 0 taken 12767 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 40 times.
✓ Branch 3 taken 12727 times.
12776 if (ret == STATE_MACHINE_FAILED || ret == STATE_MACHINE_DONE) {
5743
1/2
✓ Branch 0 taken 49 times.
✗ Branch 1 not taken.
49 my_free(ctx);
5744
2/6
✓ Branch 0 taken 49 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 49 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
49 ASYNC_DATA(mysql)->connect_context->auth_context = nullptr;
5745 }
5746
5747 12776 return ret;
5748 12776 }
5749
5750 /**
5751 Determine the default/initial plugin to use
5752 */
5753 383047 static mysql_state_machine_status authsm_begin_plugin_auth(
5754 mysql_async_auth *ctx) {
5755
1/2
✓ Branch 0 taken 383201 times.
✗ Branch 1 not taken.
383047 DBUG_TRACE;
5756 383201 MYSQL *mysql = ctx->mysql;
5757 383201 ctx->auth_plugin_name = nullptr;
5758
1/2
✓ Branch 0 taken 383201 times.
✗ Branch 1 not taken.
383201 if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH &&
5759
2/2
✓ Branch 0 taken 382868 times.
✓ Branch 1 taken 333 times.
383201 ctx->data_plugin != nullptr) {
5760 /*
5761 LDAP SASL Kerberos and Native Karberos plug-in depends on client side set
5762 default plug-in to obtained user name from credential cache. If we don't
5763 use client side authentication plug-in, user and password less
5764 functionality will not work. And this is very important feature for
5765 Kerberos.
5766
5767 We are not overriding client side default authentication plug-in if
5768 it is configured in the client side. Once server supports configuration of
5769 all the authentication plug-ins as default, Below code shall be removed.
5770 Checks:
5771 1. Default authentication plug-in is configured
5772 2. Default authentication plug-in is valid.
5773 */
5774 382868 auth_plugin_t *client_plugin{nullptr};
5775
5/6
✓ Branch 0 taken 382885 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 176 times.
✓ Branch 3 taken 382709 times.
✓ Branch 4 taken 172 times.
✓ Branch 5 taken 382696 times.
383044 if (mysql->options.extension && mysql->options.extension->default_auth &&
5776
2/2
✓ Branch 0 taken 172 times.
✓ Branch 1 taken 4 times.
176 (client_plugin = (auth_plugin_t *)mysql_client_find_plugin(
5777
1/2
✓ Branch 0 taken 176 times.
✗ Branch 1 not taken.
176 mysql, mysql->options.extension->default_auth,
5778 MYSQL_CLIENT_AUTHENTICATION_PLUGIN))) {
5779 172 ctx->auth_plugin_name = mysql->options.extension->default_auth;
5780 } else {
5781 382696 ctx->auth_plugin_name = ctx->data_plugin;
5782 }
5783
2/4
✓ Branch 0 taken 382859 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 382859 times.
382868 if (!(ctx->auth_plugin = (auth_plugin_t *)mysql_client_find_plugin(
5784 mysql, ctx->auth_plugin_name,
5785 MYSQL_CLIENT_AUTHENTICATION_PLUGIN))) {
5786 /*
5787 Client didn't recognize the server default plugin.
5788 Fallback on any client plugin set as the default.
5789 */
5790 if (mysql->options.extension && mysql->options.extension->default_auth) {
5791 ctx->auth_plugin_name = mysql->options.extension->default_auth;
5792 if (!(ctx->auth_plugin = (auth_plugin_t *)mysql_client_find_plugin(
5793 mysql, ctx->auth_plugin_name,
5794 MYSQL_CLIENT_AUTHENTICATION_PLUGIN)))
5795 return STATE_MACHINE_FAILED; /* oops, not found */
5796 }
5797 }
5798 }
5799
5800
3/4
✓ Branch 0 taken 382867 times.
✓ Branch 1 taken 325 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 382887 times.
383192 if (ctx->auth_plugin_name == nullptr || ctx->auth_plugin == nullptr) {
5801 /*
5802 If everything else fail we use the built in plugin
5803 */
5804 305 ctx->auth_plugin = &caching_sha2_password_client_plugin;
5805 305 ctx->auth_plugin_name = ctx->auth_plugin->name;
5806 }
5807
5808
2/4
✓ Branch 0 taken 383083 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 383083 times.
383192 if (check_plugin_enabled(mysql, ctx)) return STATE_MACHINE_FAILED;
5809
5810
3/8
✓ Branch 0 taken 383158 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 383183 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 383183 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
383083 DBUG_PRINT("info", ("using plugin %s", ctx->auth_plugin_name));
5811
5812 383160 mysql->net.last_errno = 0; /* just in case */
5813
5814 /*
5815 data_plugin has the plugin the server wants us to use and
5816 auth_plugin_name has the plugin we think we will need.
5817 Server doesn't know what user the client will send yet.
5818 so client knows more than the server - hence we should use
5819 auth_plugin_name if it is different from ctx->data_plugin
5820 */
5821
4/4
✓ Branch 0 taken 382850 times.
✓ Branch 1 taken 310 times.
✓ Branch 2 taken 126 times.
✓ Branch 3 taken 382724 times.
383160 if (ctx->data_plugin && strcmp(ctx->data_plugin, ctx->auth_plugin_name)) {
5822 126 ctx->data = nullptr;
5823 126 ctx->data_len = 0;
5824 }
5825
5826 383160 ctx->mpvio.mysql_change_user = ctx->data_plugin == nullptr;
5827 383160 ctx->mpvio.cached_server_reply.pkt = (uchar *)ctx->data;
5828 383160 ctx->mpvio.cached_server_reply.pkt_len = ctx->data_len;
5829 /*
5830 Sometimes plugin provided data (like scramble) can be optional, in such a
5831 case we set pkt_received flag to false based on data length. This flag is
5832 later checked in client_mpvio_read_packet() to decide on to read from
5833 network or return the cached data.
5834 */
5835
2/2
✓ Branch 0 taken 431 times.
✓ Branch 1 taken 382729 times.
383160 if (ctx->data_len == 0)
5836 431 ctx->mpvio.cached_server_reply.pkt_received = false;
5837 else
5838 382729 ctx->mpvio.cached_server_reply.pkt_received = true;
5839 383160 ctx->mpvio.read_packet = client_mpvio_read_packet;
5840 383160 ctx->mpvio.write_packet = client_mpvio_write_packet;
5841 383160 ctx->mpvio.read_packet_nonblocking = client_mpvio_read_packet_nonblocking;
5842 383160 ctx->mpvio.write_packet_nonblocking = client_mpvio_write_packet_nonblocking;
5843 383160 ctx->mpvio.info = client_mpvio_info;
5844 383160 ctx->mpvio.mysql = mysql;
5845 383160 ctx->mpvio.packets_read = ctx->mpvio.packets_written = 0;
5846 383160 ctx->mpvio.db = ctx->db;
5847 383160 ctx->mpvio.plugin = ctx->auth_plugin;
5848 383160 ctx->client_auth_plugin_state =
5849 (int)(client_auth_caching_sha2_password_plugin_status::
5850 CACHING_SHA2_READING_PASSWORD);
5851
5852 383160 ctx->state_function = authsm_run_first_authenticate_user;
5853 383160 return STATE_MACHINE_CONTINUE;
5854 383160 }
5855
5856 /**
5857 Authentication can have two authenticate_user calls, depending on
5858 what the server responds with; this handles the first.
5859 */
5860 384056 static mysql_state_machine_status authsm_run_first_authenticate_user(
5861 mysql_async_auth *ctx) {
5862
1/2
✓ Branch 0 taken 384183 times.
✗ Branch 1 not taken.
384056 DBUG_TRACE;
5863 384183 MYSQL *mysql = ctx->mysql;
5864
2/8
✓ Branch 0 taken 372699 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 372701 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
372696 MYSQL_TRACE(AUTH_PLUGIN, mysql, (ctx->auth_plugin->name));
5865
5866
3/4
✓ Branch 0 taken 1038 times.
✓ Branch 1 taken 383150 times.
✓ Branch 2 taken 1038 times.
✗ Branch 3 not taken.
384188 if (ctx->non_blocking && ctx->auth_plugin->authenticate_user_nonblocking) {
5867 2076 net_async_status status = ctx->auth_plugin->authenticate_user_nonblocking(
5868
1/2
✓ Branch 0 taken 1038 times.
✗ Branch 1 not taken.
1038 (struct MYSQL_PLUGIN_VIO *)&ctx->mpvio, mysql, &ctx->res);
5869
2/2
✓ Branch 0 taken 989 times.
✓ Branch 1 taken 49 times.
1038 if (status == NET_ASYNC_NOT_READY) {
5870 989 return STATE_MACHINE_WOULD_BLOCK;
5871 }
5872 49 } else {
5873 383084 ctx->res = ctx->auth_plugin->authenticate_user(
5874
1/2
✓ Branch 0 taken 383084 times.
✗ Branch 1 not taken.
383150 (struct MYSQL_PLUGIN_VIO *)&ctx->mpvio, mysql);
5875 }
5876
5877 383133 ctx->state_function = authsm_handle_first_authenticate_user;
5878 383133 return STATE_MACHINE_CONTINUE;
5879 384122 }
5880
5881 /**
5882 Handle the result of the first authenticate_user.
5883 */
5884 383123 static mysql_state_machine_status authsm_handle_first_authenticate_user(
5885 mysql_async_auth *ctx) {
5886
1/2
✓ Branch 0 taken 383208 times.
✗ Branch 1 not taken.
383123 DBUG_TRACE;
5887 383208 MYSQL *mysql = ctx->mysql;
5888
3/14
✓ Branch 0 taken 383196 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 383201 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 383201 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
383208 DBUG_PRINT("info",
5889 ("authenticate_user returned %s",
5890 ctx->res == CR_OK
5891 ? "CR_OK"
5892 : ctx->res == CR_ERROR ? "CR_ERROR"
5893 : ctx->res == CR_OK_HANDSHAKE_COMPLETE
5894 ? "CR_OK_HANDSHAKE_COMPLETE"
5895 : "error"));
5896
5897 static_assert(CR_OK == -1, "");
5898 static_assert(CR_ERROR == 0, "");
5899
5900 /*
5901 The connection may be closed. If so: do not try to read from the buffer.
5902 If server sends OK packet without sending auth-switch first, client side
5903 auth plugin may not be able to process it correctly.
5904 However, if server sends OK, it means server side authentication plugin
5905 already performed required checks. Further, server side plugin did not
5906 really care about plugin used by client in this case.
5907 */
5908
4/4
✓ Branch 0 taken 1533 times.
✓ Branch 1 taken 381608 times.
✓ Branch 2 taken 285 times.
✓ Branch 3 taken 382856 times.
384674 if (ctx->res > CR_OK &&
5909
2/2
✓ Branch 0 taken 1532 times.
✓ Branch 1 taken 1 times.
1533 (!my_net_is_inited(&mysql->net) ||
5910
3/4
✓ Branch 0 taken 1532 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 284 times.
✓ Branch 3 taken 1248 times.
1532 (mysql->net.read_pos[0] != 0 && mysql->net.read_pos[0] != 254))) {
5911 /*
5912 the plugin returned an error. write it down in mysql,
5913 unless the error code is CR_ERROR and mysql->net.last_errno
5914 is already set (the plugin has done it)
5915 */
5916
3/8
✓ Branch 0 taken 285 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 285 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 285 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
285 DBUG_PRINT("info", ("res=%d", ctx->res));
5917
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 285 times.
285 if (ctx->res > CR_ERROR)
5918 set_mysql_error(mysql, ctx->res, unknown_sqlstate);
5919
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 285 times.
285 else if (!mysql->net.last_errno)
5920 set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
5921 285 return STATE_MACHINE_FAILED;
5922 }
5923 382856 ctx->state_function = authsm_read_change_user_result;
5924 382856 return STATE_MACHINE_CONTINUE;
5925 383141 }
5926
5927 /**
5928 After the first authenticate_user comes a call to read the result of the
5929 implied change_user.
5930 */
5931 394352 static mysql_state_machine_status authsm_read_change_user_result(
5932 mysql_async_auth *ctx) {
5933
1/2
✓ Branch 0 taken 394433 times.
✗ Branch 1 not taken.
394352 DBUG_TRACE;
5934 394433 MYSQL *mysql = ctx->mysql;
5935 /* read the OK packet (or use the cached value in mysql->net.read_pos */
5936
2/2
✓ Branch 0 taken 393185 times.
✓ Branch 1 taken 1248 times.
394433 if (ctx->res == CR_OK) {
5937
2/2
✓ Branch 0 taken 11554 times.
✓ Branch 1 taken 381631 times.
393185 if (ctx->non_blocking) {
5938 net_async_status status =
5939
1/2
✓ Branch 0 taken 11554 times.
✗ Branch 1 not taken.
11554 (*mysql->methods->read_change_user_result_nonblocking)(
5940 mysql, &ctx->pkt_length);
5941
2/2
✓ Branch 0 taken 11508 times.
✓ Branch 1 taken 46 times.
11554 if (status == NET_ASYNC_NOT_READY) {
5942 11508 return STATE_MACHINE_WOULD_BLOCK;
5943 }
5944 } else {
5945
1/2
✓ Branch 0 taken 381547 times.
✗ Branch 1 not taken.
381631 ctx->pkt_length = (*mysql->methods->read_change_user_result)(mysql);
5946 }
5947 } else /* res == CR_OK_HANDSHAKE_COMPLETE */
5948 1248 ctx->pkt_length = ctx->mpvio.last_read_packet_len;
5949
5950 382841 ctx->state_function = authsm_handle_change_user_result;
5951 382841 return STATE_MACHINE_CONTINUE;
5952 394349 }
5953
5954 /**
5955 Check if server asked to use a different authentication plugin
5956 */
5957 382838 static mysql_state_machine_status authsm_handle_change_user_result(
5958 mysql_async_auth *ctx) {
5959
1/2
✓ Branch 0 taken 382920 times.
✗ Branch 1 not taken.
382838 DBUG_TRACE;
5960 382920 MYSQL *mysql = ctx->mysql;
5961
3/8
✓ Branch 0 taken 382914 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 382907 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 382907 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
382920 DBUG_PRINT("info", ("OK packet length=%lu", ctx->pkt_length));
5962
2/2
✓ Branch 0 taken 1772 times.
✓ Branch 1 taken 381120 times.
382892 if (ctx->pkt_length == packet_error) {
5963
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 1751 times.
1772 if (mysql->net.last_errno == CR_SERVER_LOST)
5964
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
5965 ER_CLIENT(CR_SERVER_LOST_EXTENDED),
5966 21 "reading authorization packet", errno);
5967 1772 return STATE_MACHINE_FAILED;
5968 }
5969
5970
2/2
✓ Branch 0 taken 3335 times.
✓ Branch 1 taken 377785 times.
381120 if (mysql->net.read_pos[0] == 254) {
5971 3335 ctx->state_function = authsm_run_second_authenticate_user;
5972
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 377728 times.
377785 } else if (is_auth_next_factor_packet(mysql)) {
5973 ctx->state_function = authsm_init_multi_auth;
5974 } else {
5975
2/2
✓ Branch 0 taken 377720 times.
✓ Branch 1 taken 18 times.
377728 if (is_OK_packet(mysql, ctx->pkt_length)) {
5976
1/2
✓ Branch 0 taken 377758 times.
✗ Branch 1 not taken.
377720 read_ok_ex(mysql, ctx->pkt_length);
5977 377758 ctx->state_function = authsm_finish_auth;
5978 }
5979 }
5980
5981 381111 return STATE_MACHINE_CONTINUE;
5982 382883 }
5983
5984 /**
5985 Start the authentication process again with the plugin which
5986 server asked for.
5987 */
5988 3335 static mysql_state_machine_status authsm_run_second_authenticate_user(
5989 mysql_async_auth *ctx) {
5990
1/2
✓ Branch 0 taken 3335 times.
✗ Branch 1 not taken.
3335 DBUG_TRACE;
5991 3335 MYSQL *mysql = ctx->mysql;
5992 /* The server asked to use a different authentication plugin */
5993
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3335 times.
3335 if (ctx->pkt_length < 2) {
5994 set_mysql_error(mysql, CR_MALFORMED_PACKET,
5995 unknown_sqlstate); /* purecov: inspected */
5996 return STATE_MACHINE_FAILED;
5997 } else {
5998 /* "use different plugin" packet */
5999 uint len;
6000 3335 ctx->auth_plugin_name = (char *)mysql->net.read_pos + 1;
6001 3335 len = (uint)strlen(
6002 ctx->auth_plugin_name); /* safe as my_net_read always appends \0 */
6003 3335 ctx->mpvio.cached_server_reply.pkt_len = ctx->pkt_length - len - 2;
6004 3335 ctx->mpvio.cached_server_reply.pkt = mysql->net.read_pos + len + 2;
6005 3335 ctx->mpvio.cached_server_reply.pkt_received = true;
6006
3/8
✓ Branch 0 taken 3335 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3335 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3335 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
3335 DBUG_PRINT("info", ("change plugin packet from server for plugin %s",
6007 ctx->auth_plugin_name));
6008 }
6009
2/4
✓ Branch 0 taken 3335 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3335 times.
3335 if (!(ctx->auth_plugin = (auth_plugin_t *)mysql_client_find_plugin(
6010 mysql, ctx->auth_plugin_name, MYSQL_CLIENT_AUTHENTICATION_PLUGIN)))
6011 return STATE_MACHINE_FAILED;
6012
6013
3/4
✓ Branch 0 taken 3335 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 3331 times.
3335 if (check_plugin_enabled(mysql, ctx)) return STATE_MACHINE_FAILED;
6014
6015
2/8
✓ Branch 0 taken 3137 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 3137 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
3137 MYSQL_TRACE(AUTH_PLUGIN, mysql, (ctx->auth_plugin->name));
6016
6017
2/6
✓ Branch 0 taken 3331 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3331 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
3331 DBUG_EXECUTE_IF("simulate_fido_testing", {
6018 bool is_fido_testing = true;
6019 mysql_plugin_options((struct st_mysql_client_plugin *)ctx->auth_plugin,
6020 "is_fido_testing", &is_fido_testing);
6021 });
6022 3331 ctx->mpvio.plugin = ctx->auth_plugin;
6023 6662 ctx->res = ctx->auth_plugin->authenticate_user(
6024
1/2
✓ Branch 0 taken 3331 times.
✗ Branch 1 not taken.
3331 (struct MYSQL_PLUGIN_VIO *)&ctx->mpvio, mysql);
6025
6026 3331 ctx->state_function = authsm_handle_second_authenticate_user;
6027 3331 return STATE_MACHINE_CONTINUE;
6028 3335 }
6029
6030 /* Now read the results. */
6031 3331 static mysql_state_machine_status authsm_handle_second_authenticate_user(
6032 mysql_async_auth *ctx) {
6033
1/2
✓ Branch 0 taken 3331 times.
✗ Branch 1 not taken.
3331 DBUG_TRACE;
6034 3331 MYSQL *mysql = ctx->mysql;
6035
3/14
✓ Branch 0 taken 3331 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3331 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3331 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
3331 DBUG_PRINT("info",
6036 ("second authenticate_user returned %s",
6037 ctx->res == CR_OK
6038 ? "CR_OK"
6039 : ctx->res == CR_ERROR ? "CR_ERROR"
6040 : ctx->res == CR_OK_HANDSHAKE_COMPLETE
6041 ? "CR_OK_HANDSHAKE_COMPLETE"
6042 : "error"));
6043
2/2
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 3278 times.
3331 if (ctx->res > CR_OK) {
6044
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53 times.
53 if (ctx->res > CR_ERROR)
6045 set_mysql_error(mysql, ctx->res, unknown_sqlstate);
6046
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53 times.
53 else if (!mysql->net.last_errno)
6047 set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
6048 53 return STATE_MACHINE_FAILED;
6049 }
6050
6051
1/2
✓ Branch 0 taken 3278 times.
✗ Branch 1 not taken.
3278 if (ctx->res != CR_OK_HANDSHAKE_COMPLETE) {
6052 /* Read what server thinks about out new auth message report */
6053
3/4
✓ Branch 0 taken 3278 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 503 times.
✓ Branch 3 taken 2775 times.
3278 if ((ctx->pkt_length = cli_safe_read(mysql, nullptr)) == packet_error) {
6054
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 503 times.
503 if (mysql->net.last_errno == CR_SERVER_LOST)
6055 set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
6056 ER_CLIENT(CR_SERVER_LOST_EXTENDED),
6057 "reading final connect information", errno);
6058 503 return STATE_MACHINE_FAILED;
6059 }
6060
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2775 times.
2775 if (is_auth_next_factor_packet(mysql)) {
6061 ctx->state_function = authsm_init_multi_auth;
6062 return STATE_MACHINE_CONTINUE;
6063
1/2
✓ Branch 0 taken 2775 times.
✗ Branch 1 not taken.
2775 } else if (is_OK_packet(mysql, ctx->pkt_length)) {
6064
1/2
✓ Branch 0 taken 2775 times.
✗ Branch 1 not taken.
2775 read_ok_ex(mysql, ctx->pkt_length);
6065 } else {
6066 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
6067 return STATE_MACHINE_FAILED;
6068 }
6069 }
6070 2775 ctx->state_function = authsm_finish_auth;
6071 2775 return STATE_MACHINE_CONTINUE;
6072 3331 }
6073
6074 /* Final cleanup */
6075 380462 static mysql_state_machine_status authsm_finish_auth(mysql_async_auth *ctx) {
6076
1/2
✓ Branch 0 taken 380591 times.
✗ Branch 1 not taken.
380462 DBUG_TRACE;
6077 380591 MYSQL *mysql = ctx->mysql;
6078 /*
6079 net->read_pos[0] should always be 0 here if the server implements
6080 the protocol correctly
6081 */
6082 380591 ctx->res = (mysql->net.read_pos[0] != 0);
6083
6084
3/8
✓ Branch 0 taken 369396 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 369397 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
369397 MYSQL_TRACE(AUTHENTICATED, mysql, ());
6085
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 380591 times.
761173 return ctx->res ? STATE_MACHINE_FAILED : STATE_MACHINE_DONE;
6086 380591 }
6087
6088 /** Start multi factor authentication */
6089 static mysql_state_machine_status authsm_init_multi_auth(
6090 mysql_async_auth *ctx) {
6091 DBUG_TRACE;
6092 MYSQL *mysql = ctx->mysql;
6093 /*
6094 If previous factor authentication is a success, read AuthNextFactor packet,
6095 extract client plugin name and plugin specific data and initiate next factor
6096 authentication.
6097 */
6098 size_t len;
6099 ctx->auth_plugin_name = (char *)mysql->net.read_pos + 1;
6100 len = strlen(ctx->auth_plugin_name);
6101 /* adjust cached plugin data packet */
6102 ctx->mpvio.cached_server_reply.pkt_len = ctx->pkt_length - len - 2;
6103 ctx->mpvio.cached_server_reply.pkt = mysql->net.read_pos + len + 2;
6104 ctx->mpvio.cached_server_reply.pkt_received = true;
6105 DBUG_PRINT("info", ("AuthNextFactor plugin packet from server %s",
6106 ctx->auth_plugin_name));
6107
6108 /* update current factor index to point to nth factor */
6109 ctx->current_factor_index++;
6110 if (!(ctx->auth_plugin = (auth_plugin_t *)mysql_client_find_plugin(
6111 mysql, ctx->auth_plugin_name,
6112 MYSQL_CLIENT_AUTHENTICATION_PLUGIN))) {
6113 set_mysql_extended_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD,
6114 unknown_sqlstate,
6115 ER_CLIENT(CR_AUTH_PLUGIN_CANNOT_LOAD),
6116 ctx->auth_plugin_name, "plugin not available");
6117 return STATE_MACHINE_FAILED;
6118 }
6119 if (mysql->options.extension) {
6120 char **plugin_name =
6121 &mysql->options.extension->client_auth_info[ctx->current_factor_index]
6122 .plugin_name;
6123 *plugin_name = static_cast<char *>(
6124 my_malloc(PSI_NOT_INSTRUMENTED, len + 1, MYF(MY_WME | MY_ZEROFILL)));
6125 if (!*plugin_name) {
6126 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
6127 return STATE_MACHINE_FAILED;
6128 }
6129 memcpy(*plugin_name, ctx->auth_plugin_name, len);
6130 }
6131 DBUG_EXECUTE_IF("simulate_fido_testing", {
6132 bool is_fido_testing = true;
6133 mysql_plugin_options((struct st_mysql_client_plugin *)ctx->auth_plugin,
6134 "is_fido_testing", &is_fido_testing);
6135 });
6136 /* check if plugin is enabled */
6137 if (check_plugin_enabled(mysql, ctx)) return STATE_MACHINE_FAILED;
6138
6139 /* reset password for next client auth plugin */
6140 if (mysql->passwd) mysql->passwd[0] = 0;
6141 /* get password */
6142 if (mysql->options.extension &&
6143 mysql->options.extension->client_auth_info[ctx->current_factor_index]
6144 .password) {
6145 my_free(mysql->passwd);
6146 mysql->passwd = my_strdup(
6147 key_memory_MYSQL,
6148 mysql->options.extension->client_auth_info[ctx->current_factor_index]
6149 .password,
6150 MYF(0));
6151 }
6152 ctx->state_function = authsm_do_multi_plugin_auth;
6153 return STATE_MACHINE_CONTINUE;
6154 }
6155
6156 /** Invoke client plugins authentication method */
6157 static mysql_state_machine_status authsm_do_multi_plugin_auth(
6158 mysql_async_auth *ctx) {
6159 DBUG_TRACE;
6160 MYSQL *mysql = ctx->mysql;
6161 MYSQL_TRACE(AUTH_PLUGIN, mysql, (ctx->auth_plugin->name));
6162
6163 ctx->mpvio.plugin = ctx->auth_plugin;
6164 ctx->res = ctx->auth_plugin->authenticate_user(
6165 (struct MYSQL_PLUGIN_VIO *)&ctx->mpvio, mysql);
6166
6167 ctx->state_function = authsm_handle_multi_auth_response;
6168 return STATE_MACHINE_CONTINUE;
6169 }
6170
6171 /** Handle response from client plugins authentication method */
6172 static mysql_state_machine_status authsm_handle_multi_auth_response(
6173 mysql_async_auth *ctx) {
6174 DBUG_TRACE;
6175 MYSQL *mysql = ctx->mysql;
6176
6177 if (ctx->res > CR_OK) {
6178 if (ctx->res > CR_ERROR)
6179 set_mysql_error(mysql, ctx->res, unknown_sqlstate);
6180 else if (!mysql->net.last_errno)
6181 set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
6182 return STATE_MACHINE_FAILED;
6183 }
6184
6185 if (ctx->res != CR_OK_HANDSHAKE_COMPLETE) {
6186 /* Read what server thinks about new auth message report */
6187 if ((ctx->pkt_length = cli_safe_read(mysql, nullptr)) == packet_error) {
6188 if (mysql->net.last_errno == CR_SERVER_LOST)
6189 set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
6190 ER_CLIENT(CR_SERVER_LOST_EXTENDED),
6191 "reading final connect information", errno);
6192 return STATE_MACHINE_FAILED;
6193 }
6194 if (is_auth_next_factor_packet(mysql)) {
6195 ctx->state_function = authsm_init_multi_auth;
6196 return STATE_MACHINE_CONTINUE;
6197 } else if (is_OK_packet(mysql, ctx->pkt_length)) {
6198 read_ok_ex(mysql, ctx->pkt_length);
6199 } else {
6200 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
6201 return STATE_MACHINE_FAILED;
6202 }
6203 }
6204 ctx->state_function = authsm_finish_auth;
6205 assert(ctx->current_factor_index < 3);
6206 return STATE_MACHINE_CONTINUE;
6207 }
6208
6209 /** set some default attributes */
6210 2049867 static int set_connect_attributes(MYSQL *mysql, char *buff, size_t buf_len) {
6211
1/2
✓ Branch 0 taken 2050131 times.
✗ Branch 1 not taken.
2049867 DBUG_TRACE;
6212 2050131 int rc = 0;
6213
6214 /*
6215 Clean up any values set by the client code. We want these options as
6216 consistent as possible
6217 */
6218
1/2
✓ Branch 0 taken 2050097 times.
✗ Branch 1 not taken.
2050131 rc += mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_client_name");
6219
1/2
✓ Branch 0 taken 2050128 times.
✗ Branch 1 not taken.
2050097 rc += mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_os");
6220
1/2
✓ Branch 0 taken 2050094 times.
✗ Branch 1 not taken.
2050128 rc += mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_platform");
6221
1/2
✓ Branch 0 taken 2050122 times.
✗ Branch 1 not taken.
2050094 rc += mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_pid");
6222
1/2
✓ Branch 0 taken 2050137 times.
✗ Branch 1 not taken.
2050122 rc += mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_thread");
6223
1/2
✓ Branch 0 taken 2050141 times.
✗ Branch 1 not taken.
2050137 rc += mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_client_version");
6224
6225 /*
6226 Now let's set up some values
6227 */
6228
1/2
✓ Branch 0 taken 2049985 times.
✗ Branch 1 not taken.
2050141 rc += mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_client_name",
6229 "libmysql");
6230
1/2
✓ Branch 0 taken 2050102 times.
✗ Branch 1 not taken.
2049985 rc += mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_client_version",
6231 PACKAGE_VERSION);
6232
1/2
✓ Branch 0 taken 2050092 times.
✗ Branch 1 not taken.
2050102 rc += mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_os", SYSTEM_TYPE);
6233
1/2
✓ Branch 0 taken 2050100 times.
✗ Branch 1 not taken.
2050092 rc += mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_platform",
6234 MACHINE_TYPE);
6235 #ifdef _WIN32
6236 snprintf(buff, buf_len, "%lu", (ulong)GetCurrentProcessId());
6237 #else
6238 2050100 snprintf(buff, buf_len, "%lu", (ulong)getpid());
6239 #endif
6240
1/2
✓ Branch 0 taken 2050050 times.
✗ Branch 1 not taken.
2050042 rc += mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_pid", buff);
6241
6242 #ifdef _WIN32
6243 snprintf(buff, buf_len, "%lu", (ulong)GetCurrentThreadId());
6244 rc += mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_thread", buff);
6245 #endif
6246
6247
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2050050 times.
4100164 return rc > 0 ? 1 : 0;
6248 2050050 }
6249
6250 2049825 MYSQL *STDCALL mysql_real_connect(MYSQL *mysql, const char *host,
6251 const char *user, const char *passwd,
6252 const char *db, uint port,
6253 const char *unix_socket, ulong client_flag) {
6254
1/2
✓ Branch 0 taken 2050085 times.
✗ Branch 1 not taken.
2049825 DBUG_TRACE;
6255 mysql_state_machine_status status;
6256 mysql_async_connect ctx;
6257 2050085 memset(&ctx, 0, sizeof(ctx));
6258
6259 2050085 ctx.mysql = mysql;
6260 2050085 ctx.host = host;
6261 2050085 ctx.port = port;
6262 2050085 ctx.db = db;
6263 2050085 ctx.user = user;
6264
3/4
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 2050066 times.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
2050085 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
6265 /* password will be extracted from mysql options */
6266
2/2
✓ Branch 0 taken 240962 times.
✓ Branch 1 taken 1809123 times.
2050085 if (mysql->options.extension->client_auth_info[0].password)
6267 240962 ctx.passwd = mysql->options.extension->client_auth_info[0].password;
6268 else
6269 1809123 ctx.passwd = passwd;
6270 2050085 ctx.unix_socket = unix_socket;
6271 2050085 mysql->options.client_flag |= client_flag;
6272 2050085 ctx.client_flag = mysql->options.client_flag;
6273 2050085 ctx.state_function = csm_begin_connect;
6274 2050085 ctx.ssl_state = SSL_NONE;
6275
6276 do {
6277
1/2
✓ Branch 0 taken 4714170 times.
✗ Branch 1 not taken.
4714157 status = ctx.state_function(&ctx);
6278
4/4
✓ Branch 0 taken 3045001 times.
✓ Branch 1 taken 1669169 times.
✓ Branch 2 taken 2664072 times.
✓ Branch 3 taken 380929 times.
4714170 } while (status != STATE_MACHINE_FAILED && status != STATE_MACHINE_DONE);
6279
6280
2/2
✓ Branch 0 taken 380310 times.
✓ Branch 1 taken 1669788 times.
2050098 if (status == STATE_MACHINE_DONE) {
6281
3/8
✓ Branch 0 taken 380303 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 380298 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 380298 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
380310 DBUG_PRINT("exit", ("Mysql handler: %p", mysql));
6282 380295 return mysql;
6283 }
6284
6285
3/8
✓ Branch 0 taken 1669788 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1669788 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1669788 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1669788 DBUG_PRINT("error", ("message: %u/%s (%s)", mysql->net.last_errno,
6286 mysql->net.sqlstate, mysql->net.last_error));
6287 {
6288 /* Free allocated memory */
6289
1/2
✓ Branch 0 taken 1669788 times.
✗ Branch 1 not taken.
1669788 end_server(mysql);
6290
1/2
✓ Branch 0 taken 1669788 times.
✗ Branch 1 not taken.
1669788 mysql_close_free(mysql);
6291
2/2
✓ Branch 0 taken 5646 times.
✓ Branch 1 taken 1664142 times.
1669788 if (!(ctx.client_flag & CLIENT_REMEMBER_OPTIONS))
6292
1/2
✓ Branch 0 taken 5646 times.
✗ Branch 1 not taken.
5646 mysql_close_free_options(mysql);
6293
3/4
✓ Branch 0 taken 1565 times.
✓ Branch 1 taken 1668223 times.
✓ Branch 2 taken 1565 times.
✗ Branch 3 not taken.
1669788 if (ctx.scramble_buffer_allocated) my_free(ctx.scramble_buffer);
6294 }
6295 1669788 return nullptr;
6296 2050083 }
6297
6298 /**
6299 This API attempts to initialize all the context needed to make an asynchronous
6300 connection followed by establishing a connection to MySQL database. If this
6301 API returns NET_ASYNC_COMPLETE then connection is established else call this
6302 API from the client application until the status returned is
6303 NET_ASYNC_COMPLETE.
6304
6305 @param[in] mysql connection handle
6306 @param[in] host host name or IP address
6307 @param[in] user login ID used to connect to host
6308 @param[in] passwd password for this login ID
6309 @param[in] db default database to be set after connection
6310 @param[in] port port number to use for connection
6311 @param[in] unix_socket socket file to use for connection
6312 @param[in] client_flag flag to indidcate what client can handle
6313
6314 @retval NET_ASYNC_COMPLETE Success.
6315 @retval NET_ASYNC_ERROR Error.
6316 */
6317 47326 net_async_status STDCALL mysql_real_connect_nonblocking(
6318 MYSQL *mysql, const char *host, const char *user, const char *passwd,
6319 const char *db, uint port, const char *unix_socket, ulong client_flag) {
6320
1/2
✓ Branch 0 taken 47326 times.
✗ Branch 1 not taken.
47326 DBUG_TRACE;
6321
6322 mysql_state_machine_status status;
6323
2/6
✓ Branch 0 taken 47326 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 47326 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
47326 mysql_async_connect *ctx = ASYNC_DATA(mysql)->connect_context;
6324
6325
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 47275 times.
47326 if (!ctx) {
6326 ctx = static_cast<mysql_async_connect *>(
6327
1/2
✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
51 my_malloc(key_memory_MYSQL, sizeof(*ctx), MYF(MY_WME | MY_ZEROFILL)));
6328
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 51 times.
51 if (!ctx) return NET_ASYNC_ERROR;
6329
6330 51 ctx->mysql = mysql;
6331 51 ctx->host = host;
6332 51 ctx->port = port;
6333 51 ctx->db = db;
6334 51 ctx->user = user;
6335
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 51 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
51 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
6336 /* password will be extracted from mysql options */
6337
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 19 times.
51 if (mysql->options.extension->client_auth_info[0].password)
6338 32 ctx->passwd = mysql->options.extension->client_auth_info[0].password;
6339 else
6340 19 ctx->passwd = passwd;
6341 51 ctx->unix_socket = unix_socket;
6342 51 mysql->options.client_flag |= client_flag;
6343 51 ctx->client_flag = mysql->options.client_flag;
6344 51 ctx->non_blocking = true;
6345 51 ctx->state_function = csm_begin_connect;
6346 51 ctx->ssl_state = SSL_NONE;
6347
2/6
✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 51 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
51 ASYNC_DATA(mysql)->connect_context = ctx;
6348
2/6
✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 51 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
51 ASYNC_DATA(mysql)->async_op_status = ASYNC_OP_CONNECT;
6349 }
6350
6351 /*
6352 Continue to loop When different state returns STATE_MACHINE_CONTINUE, which
6353 means more work has to be done immediately and should not return to the
6354 caller.
6355 */
6356 do {
6357
1/2
✓ Branch 0 taken 47887 times.
✗ Branch 1 not taken.
47887 status = ctx->state_function(ctx);
6358
2/2
✓ Branch 0 taken 561 times.
✓ Branch 1 taken 47326 times.
47887 } while (status == STATE_MACHINE_CONTINUE);
6359
6360
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 47286 times.
47326 if (status == STATE_MACHINE_DONE) {
6361
3/8
✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 40 times.
✗ Branch 7 not taken.
40 my_free(ASYNC_DATA(mysql)->connect_context);
6362
2/6
✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
40 ASYNC_DATA(mysql)->connect_context = nullptr;
6363
2/6
✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
40 ASYNC_DATA(mysql)->async_op_status = ASYNC_OP_UNSET;
6364 40 return NET_ASYNC_COMPLETE;
6365 }
6366
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 47276 times.
47286 if (status == STATE_MACHINE_FAILED) {
6367
3/8
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
10 DBUG_PRINT("error", ("message: %u/%s (%s)", mysql->net.last_errno,
6368 mysql->net.sqlstate, mysql->net.last_error));
6369 /* Free allocated memory */
6370
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 end_server(mysql);
6371
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 mysql_close_free(mysql);
6372
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if (!(mysql->options.client_flag & CLIENT_REMEMBER_OPTIONS))
6373
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 mysql_close_free_options(mysql);
6374 10 return NET_ASYNC_ERROR;
6375 }
6376 /*
6377 State machine returned STATE_MACHINE_WOULD_BLOCK, thus expecting caller to
6378 call this function again to continue with state machine once pending IO is
6379 completed.
6380 */
6381 47276 return NET_ASYNC_NOT_READY;
6382 47326 }
6383 /**
6384 Begin the connection to the server, including any DNS resolution
6385 necessary, socket configuration, etc.
6386 */
6387 2049873 static mysql_state_machine_status csm_begin_connect(mysql_async_connect *ctx) {
6388 2049873 MYSQL *mysql = ctx->mysql;
6389 2049873 const char *host = ctx->host;
6390 2049873 const char *user = ctx->user;
6391 2049873 const char *passwd = ctx->passwd;
6392 2049873 const char *db = ctx->db;
6393 2049873 uint port = ctx->port;
6394 2049873 const char *unix_socket = ctx->unix_socket;
6395 2049873 ulong client_flag = ctx->client_flag;
6396 2049873 bool connect_done =
6397 true; // this is true for most of the connect methods except sockets
6398
6399
1/2
✓ Branch 0 taken 2050140 times.
✗ Branch 1 not taken.
2049873 DBUG_TRACE;
6400
6401
3/14
✓ Branch 0 taken 2050106 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2050091 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2050091 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
2050140 DBUG_PRINT("enter",
6402 ("host: %s db: %s user: %s (client)", host ? host : "(Null)",
6403 db ? db : "(Null)", user ? user : "(Null)"));
6404
6405 2049987 NET *net = &mysql->net;
6406 #ifdef _WIN32
6407 HANDLE hPipe = INVALID_HANDLE_VALUE;
6408 #endif
6409 #ifdef HAVE_SYS_UN_H
6410 struct sockaddr_un UNIXaddr;
6411 #endif
6412 /* Test whether we're already connected */
6413
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2049986 times.
2049987 if (net->vio) {
6414
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 set_mysql_error(mysql, CR_ALREADY_CONNECTED, unknown_sqlstate);
6415 1 return STATE_MACHINE_FAILED;
6416 }
6417
6418
2/4
✓ Branch 0 taken 2050003 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2050003 times.
2049986 if (set_connect_attributes(mysql, ctx->buff, sizeof(ctx->buff)))
6419 return STATE_MACHINE_FAILED;
6420
6421 2050003 mysql->methods = &client_methods;
6422 2050003 net->vio = nullptr; /* If something goes wrong */
6423 2050003 mysql->client_flag = 0; /* For handshake */
6424
6425 /* use default options */
6426
3/4
✓ Branch 0 taken 2050058 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 55 times.
✓ Branch 3 taken 2050003 times.
2050003 if (mysql->options.my_cnf_file || mysql->options.my_cnf_group) {
6427 mysql_read_default_options(
6428 &mysql->options,
6429 (mysql->options.my_cnf_file ? mysql->options.my_cnf_file : "my"),
6430 mysql->options.my_cnf_group);
6431 my_free(mysql->options.my_cnf_file);
6432 my_free(mysql->options.my_cnf_group);
6433 mysql->options.my_cnf_file = mysql->options.my_cnf_group = nullptr;
6434 }
6435
6436 /* Some empty-string-tests are done because of ODBC */
6437
4/4
✓ Branch 0 taken 2049868 times.
✓ Branch 1 taken 135 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 2049864 times.
2050003 if (!host || !host[0]) host = mysql->options.host;
6438
4/4
✓ Branch 0 taken 2049903 times.
✓ Branch 1 taken 100 times.
✓ Branch 2 taken 23 times.
✓ Branch 3 taken 2049880 times.
2050003 if (!user || !user[0]) {
6439 123 user = mysql->options.user;
6440
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 100 times.
123 if (!user) user = "";
6441 }
6442
2/2
✓ Branch 0 taken 184 times.
✓ Branch 1 taken 2049819 times.
2050003 if (!passwd) {
6443 184 passwd = mysql->options.password;
6444 #if !defined(MYSQL_SERVER)
6445
1/2
✓ Branch 0 taken 114 times.
✗ Branch 1 not taken.
114 if (!passwd) passwd = getenv("MYSQL_PWD"); /* get it from environment */
6446 #endif
6447
1/2
✓ Branch 0 taken 184 times.
✗ Branch 1 not taken.
184 if (!passwd) passwd = "";
6448 }
6449
4/4
✓ Branch 0 taken 1948105 times.
✓ Branch 1 taken 101898 times.
✓ Branch 2 taken 32209 times.
✓ Branch 3 taken 1915896 times.
2050003 if (!db || !db[0]) db = mysql->options.db;
6450
2/2
✓ Branch 0 taken 94 times.
✓ Branch 1 taken 2049909 times.
2050003 if (!port) port = mysql->options.port;
6451
2/2
✓ Branch 0 taken 268444 times.
✓ Branch 1 taken 1781559 times.
2050003 if (!unix_socket) unix_socket = mysql->options.unix_socket;
6452
6453 2050003 mysql->server_status = SERVER_STATUS_AUTOCOMMIT;
6454
3/8
✓ Branch 0 taken 2050003 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2049998 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2049998 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2050003 DBUG_PRINT("info", ("Connecting"));
6455
6456
5/14
✓ Branch 0 taken 2018225 times.
✓ Branch 1 taken 19136 times.
✓ Branch 2 taken 19136 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2037361 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 2037361 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
2037361 MYSQL_TRACE_STAGE(mysql, CONNECTING);
6457
2/8
✓ Branch 0 taken 2037086 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2037221 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2037086 MYSQL_TRACE(CONNECTING, mysql, ());
6458
6459 #if defined(_WIN32)
6460 if ((!mysql->options.protocol ||
6461 mysql->options.protocol == MYSQL_PROTOCOL_MEMORY) &&
6462 (!host || !strcmp(host, LOCAL_HOST))) {
6463 HANDLE handle_map;
6464 DBUG_PRINT("info", ("Using shared memory"));
6465
6466 handle_map =
6467 create_shared_memory(mysql, net, get_win32_connect_timeout(mysql));
6468
6469 if (handle_map == INVALID_HANDLE_VALUE) {
6470 DBUG_PRINT("error",
6471 ("host: '%s' socket: '%s' shared memory: %s have_tcpip: %d",
6472 host ? host : "<null>", unix_socket ? unix_socket : "<null>",
6473 mysql->options.shared_memory_base_name, (int)have_tcpip));
6474 if (mysql->options.protocol == MYSQL_PROTOCOL_MEMORY)
6475 return STATE_MACHINE_FAILED;
6476 /*
6477 Try also with PIPE or TCP/IP. Clear the error from
6478 create_shared_memory().
6479 */
6480
6481 net_clear_error(net);
6482 } else {
6483 mysql->options.protocol = MYSQL_PROTOCOL_MEMORY;
6484 unix_socket = 0;
6485 host = mysql->options.shared_memory_base_name;
6486 snprintf(ctx->host_info = ctx->buff, sizeof(ctx->buff) - 1,
6487 ER_CLIENT(CR_SHARED_MEMORY_CONNECTION), host);
6488 }
6489 }
6490 #endif /* _WIN32 */
6491 #if defined(HAVE_SYS_UN_H)
6492
2/2
✓ Branch 0 taken 2049864 times.
✓ Branch 1 taken 19 times.
2049883 if (!net->vio &&
6493
2/2
✓ Branch 0 taken 1421575 times.
✓ Branch 1 taken 628289 times.
2049864 (!mysql->options.protocol ||
6494
4/4
✓ Branch 0 taken 1400961 times.
✓ Branch 1 taken 20614 times.
✓ Branch 2 taken 268441 times.
✓ Branch 3 taken 1760809 times.
2049864 mysql->options.protocol == MYSQL_PROTOCOL_SOCKET) &&
6495
4/4
✓ Branch 0 taken 255799 times.
✓ Branch 1 taken 12642 times.
✓ Branch 2 taken 2016571 times.
✓ Branch 3 taken 37 times.
2029250 (unix_socket || mysql_unix_port) &&
6496
2/2
✓ Branch 0 taken 1716409 times.
✓ Branch 1 taken 300162 times.
2016571 (!host || !strcmp(host, LOCAL_HOST))) {
6497 1716446 my_socket sock = socket(AF_UNIX, SOCK_STREAM, 0);
6498
3/8
✓ Branch 0 taken 1716689 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1716676 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1716676 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1716717 DBUG_PRINT("info", ("Using socket"));
6499
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1716687 times.
1716687 if (sock == INVALID_SOCKET) {
6500 set_mysql_extended_error(mysql, CR_SOCKET_CREATE_ERROR, unknown_sqlstate,
6501 ER_CLIENT(CR_SOCKET_CREATE_ERROR), socket_errno);
6502 return STATE_MACHINE_FAILED;
6503 }
6504
6505 1716823 net->vio =
6506
1/2
✓ Branch 0 taken 1716823 times.
✗ Branch 1 not taken.
1716687 vio_new(sock, VIO_TYPE_SOCKET, VIO_LOCALHOST | VIO_BUFFERED_READ);
6507
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1716823 times.
1716823 if (!net->vio) {
6508 DBUG_PRINT("error", ("Unknow protocol %d ", mysql->options.protocol));
6509 set_mysql_error(mysql, CR_CONN_UNKNOW_PROTOCOL, unknown_sqlstate);
6510 closesocket(sock);
6511 return STATE_MACHINE_FAILED;
6512 }
6513
6514
3/4
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 1716775 times.
✓ Branch 2 taken 48 times.
✗ Branch 3 not taken.
1716823 if (ctx->non_blocking) vio_set_blocking_flag(net->vio, !ctx->non_blocking);
6515
6516 1716823 host = LOCAL_HOST;
6517
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1716823 times.
1716823 if (!unix_socket) unix_socket = mysql_unix_port;
6518 1716823 ctx->host_info = const_cast<char *>(ER_CLIENT(CR_LOCALHOST_CONNECTION));
6519
3/8
✓ Branch 0 taken 1716647 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1716766 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1716766 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1716534 DBUG_PRINT("info", ("Using UNIX sock '%s'", unix_socket));
6520
6521 1716766 memset(&UNIXaddr, 0, sizeof(UNIXaddr));
6522 1716766 UNIXaddr.sun_family = AF_UNIX;
6523
1/2
✓ Branch 0 taken 1716858 times.
✗ Branch 1 not taken.
1716766 strmake(UNIXaddr.sun_path, unix_socket, sizeof(UNIXaddr.sun_path) - 1);
6524
6525
2/4
✓ Branch 0 taken 1716863 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1716863 times.
1716858 if (mysql->options.extension && mysql->options.extension->retry_count)
6526 my_net_set_retry_count(net, mysql->options.extension->retry_count);
6527
6528
2/2
✓ Branch 0 taken 1413978 times.
✓ Branch 1 taken 302749 times.
3433585 if (vio_socket_connect(net->vio, (struct sockaddr *)&UNIXaddr,
6529
1/2
✓ Branch 0 taken 1716727 times.
✗ Branch 1 not taken.
1716552 sizeof(UNIXaddr), ctx->non_blocking,
6530 get_vio_connect_timeout(mysql), &connect_done)) {
6531
3/8
✓ Branch 0 taken 1413978 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1413978 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1413978 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1413978 DBUG_PRINT("error",
6532 ("Got error %d on connect to local server", socket_errno));
6533
1/2
✓ Branch 0 taken 1413978 times.
✗ Branch 1 not taken.
1413978 set_mysql_extended_error(mysql, CR_CONNECTION_ERROR, unknown_sqlstate,
6534 ER_CLIENT(CR_CONNECTION_ERROR), unix_socket,
6535 1413978 socket_errno);
6536
1/2
✓ Branch 0 taken 1413978 times.
✗ Branch 1 not taken.
1413978 vio_delete(net->vio);
6537 1413978 net->vio = nullptr;
6538 1413978 return STATE_MACHINE_FAILED;
6539 }
6540 302749 mysql->options.protocol = MYSQL_PROTOCOL_SOCKET;
6541 }
6542 #elif defined(_WIN32)
6543 if (!net->vio && (mysql->options.protocol == MYSQL_PROTOCOL_PIPE ||
6544 (host && !strcmp(host, LOCAL_HOST_NAMEDPIPE)) ||
6545 (!have_tcpip && (unix_socket || (!host && is_NT()))))) {
6546 hPipe = create_named_pipe(mysql, get_win32_connect_timeout(mysql), &host,
6547 &unix_socket);
6548
6549 if (hPipe == INVALID_HANDLE_VALUE) {
6550 DBUG_PRINT(
6551 "error",
6552 ("host: '%s' socket: '%s' have_tcpip: %d", host ? host : "<null>",
6553 unix_socket ? unix_socket : "<null>", (int)have_tcpip));
6554 if (mysql->options.protocol == MYSQL_PROTOCOL_PIPE ||
6555 (host && !strcmp(host, LOCAL_HOST_NAMEDPIPE)) ||
6556 (unix_socket && !strcmp(unix_socket, MYSQL_NAMEDPIPE)))
6557 return STATE_MACHINE_FAILED;
6558 /* Try also with TCP/IP */
6559 } else {
6560 net->vio = vio_new_win32pipe(hPipe);
6561 snprintf(ctx->host_info = ctx->buff, sizeof(ctx->buff) - 1,
6562 ER_CLIENT(CR_NAMEDPIPE_CONNECTION), unix_socket);
6563 }
6564 }
6565 #endif
6566
3/8
✓ Branch 0 taken 636049 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 636105 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 636105 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
636186 DBUG_PRINT("info",
6567 ("net->vio: %p protocol: %d", net->vio, mysql->options.protocol));
6568
4/4
✓ Branch 0 taken 333276 times.
✓ Branch 1 taken 302829 times.
✓ Branch 2 taken 20614 times.
✓ Branch 3 taken 312662 times.
636105 if (!net->vio && (!mysql->options.protocol ||
6569
1/2
✓ Branch 0 taken 20842 times.
✗ Branch 1 not taken.
20614 mysql->options.protocol == MYSQL_PROTOCOL_TCP)) {
6570 333508 struct addrinfo *res_lst, *client_bind_ai_lst = nullptr, hints, *t_res;
6571 char port_buf[NI_MAXSERV];
6572 333508 my_socket sock = INVALID_SOCKET;
6573 333508 int gai_errno, saved_error = 0, status = -1, bind_result = 0;
6574 333508 uint flags = VIO_BUFFERED_READ;
6575
6576 333508 unix_socket = nullptr; /* This is not used */
6577
6578
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 333418 times.
333508 if (!port) port = mysql_port;
6579
6580
2/2
✓ Branch 0 taken 95 times.
✓ Branch 1 taken 333413 times.
333508 if (!host) host = LOCAL_HOST;
6581
6582 333508 snprintf(ctx->host_info = ctx->buff, sizeof(ctx->buff) - 1,
6583 ER_CLIENT(CR_TCP_CONNECTION), host);
6584
3/8
✓ Branch 0 taken 333270 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 333273 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 333273 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
333270 DBUG_PRINT("info", ("Server name: '%s'. TCP sock: %d", host, port));
6585
6586 333273 memset(&hints, 0, sizeof(hints));
6587 333273 hints.ai_socktype = SOCK_STREAM;
6588 333273 hints.ai_protocol = IPPROTO_TCP;
6589 333273 hints.ai_family = AF_UNSPEC;
6590
6591
3/8
✓ Branch 0 taken 333273 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 333274 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 333274 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
333273 DBUG_PRINT("info", ("IPV6 getaddrinfo %s", host));
6592 333274 snprintf(port_buf, NI_MAXSERV, "%d", port);
6593
1/2
✓ Branch 0 taken 333272 times.
✗ Branch 1 not taken.
333274 gai_errno = getaddrinfo(host, port_buf, &hints, &res_lst);
6594
6595
5/8
✓ Branch 0 taken 333274 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 333267 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 7 times.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
333272 DBUG_EXECUTE_IF("vio_client_use_localhost", {
6596 assert(strlen(host) == 255);
6597 gai_errno = getaddrinfo(LOCAL_HOST, port_buf, &hints, &res_lst);
6598 });
6599
6600
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 333253 times.
333274 if (gai_errno != 0) {
6601
3/8
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 21 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
21 DBUG_PRINT("info", ("IPV6 getaddrinfo error %d", gai_errno));
6602
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 set_mysql_extended_error(mysql, CR_UNKNOWN_HOST, unknown_sqlstate,
6603 ER_CLIENT(CR_UNKNOWN_HOST), host, gai_errno);
6604 252675 return STATE_MACHINE_FAILED;
6605 }
6606
6607 /* Get address info for client bind name if it is provided */
6608
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 333233 times.
333253 if (mysql->options.bind_address) {
6609 20 int bind_gai_errno = 0;
6610
6611
3/8
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 20 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
20 DBUG_PRINT("info", ("Resolving addresses for client bind: '%s'",
6612 mysql->options.bind_address));
6613 /* Lookup address info for name */
6614
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 bind_gai_errno = getaddrinfo(mysql->options.bind_address, nullptr, &hints,
6615 &client_bind_ai_lst);
6616
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (bind_gai_errno) {
6617 DBUG_PRINT("info",
6618 ("client bind getaddrinfo error %d", bind_gai_errno));
6619 set_mysql_extended_error(mysql, CR_UNKNOWN_HOST, unknown_sqlstate,
6620 ER_CLIENT(CR_UNKNOWN_HOST),
6621 mysql->options.bind_address, bind_gai_errno);
6622
6623 freeaddrinfo(res_lst);
6624 return STATE_MACHINE_FAILED;
6625 }
6626
3/8
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 20 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
20 DBUG_PRINT("info", (" got address info for client bind name"));
6627 }
6628
6629 /*
6630 A hostname might map to multiple IP addresses (IPv4/IPv6). Go over the
6631 list of IP addresses until a successful connection can be established.
6632 For each IP address, attempt to bind the socket to each client address
6633 for the client-side bind hostname until the bind is successful.
6634 */
6635
3/8
✓ Branch 0 taken 333249 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 333252 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 333252 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
333253 DBUG_PRINT("info", ("Try connect on all addresses for host."));
6636
2/2
✓ Branch 0 taken 333248 times.
✓ Branch 1 taken 252658 times.
585906 for (t_res = res_lst; t_res; t_res = t_res->ai_next) {
6637
3/8
✓ Branch 0 taken 333249 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 333253 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 333253 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
333248 DBUG_PRINT("info",
6638 ("Create socket, family: %d type: %d proto: %d",
6639 t_res->ai_family, t_res->ai_socktype, t_res->ai_protocol));
6640
6641 333253 sock = socket(t_res->ai_family, t_res->ai_socktype, t_res->ai_protocol);
6642
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 333243 times.
333243 if (sock == INVALID_SOCKET) {
6643 DBUG_PRINT("info", ("Socket created was invalid"));
6644 /* Try next address if there is one */
6645 saved_error = socket_errno;
6646 continue;
6647 }
6648
6649
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 333223 times.
333243 if (client_bind_ai_lst) {
6650 20 struct addrinfo *curr_bind_ai = nullptr;
6651
3/8
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 20 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
20 DBUG_PRINT("info", ("Attempting to bind socket to bind address(es)"));
6652
6653 /*
6654 We'll attempt to bind to each of the addresses returned, until
6655 we find one that works.
6656 If none works, we'll try the next destination host address
6657 (if any)
6658 */
6659 20 curr_bind_ai = client_bind_ai_lst;
6660
6661
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 4 times.
24 while (curr_bind_ai != nullptr) {
6662 /* Attempt to bind the socket to the given address */
6663 20 bind_result = bind(sock, curr_bind_ai->ai_addr,
6664 static_cast<int>(curr_bind_ai->ai_addrlen));
6665
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 4 times.
20 if (!bind_result) break; /* Success */
6666
6667
3/8
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
4 DBUG_PRINT("info", ("bind failed, attempting another bind address"));
6668 /* Problem with the bind, move to next address if present */
6669 4 curr_bind_ai = curr_bind_ai->ai_next;
6670 }
6671
6672
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 16 times.
20 if (bind_result) {
6673 /*
6674 Could not bind to any client-side address with this destination
6675 Try the next destination address (if any)
6676 */
6677
3/8
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
4 DBUG_PRINT("info", ("All bind attempts with this address failed"));
6678 4 saved_error = socket_errno;
6679
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 closesocket(sock);
6680 4 continue;
6681 }
6682
3/8
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 16 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
16 DBUG_PRINT("info", ("Successfully bound client side of socket"));
6683 }
6684
6685 /* Create a new Vio object to abstract the socket. */
6686
1/2
✓ Branch 0 taken 333236 times.
✗ Branch 1 not taken.
333236 if (!net->vio) {
6687
2/4
✓ Branch 0 taken 333250 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 333250 times.
333236 if (!(net->vio = vio_new(sock, VIO_TYPE_TCPIP, flags))) {
6688 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
6689 closesocket(sock);
6690 freeaddrinfo(res_lst);
6691 if (client_bind_ai_lst) freeaddrinfo(client_bind_ai_lst);
6692 return STATE_MACHINE_FAILED;
6693 }
6694 }
6695 /* Just reinitialize if one is already allocated. */
6696 else if (vio_reset(net->vio, VIO_TYPE_TCPIP, sock, nullptr, flags)) {
6697 set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
6698 closesocket(sock);
6699 freeaddrinfo(res_lst);
6700 if (client_bind_ai_lst) freeaddrinfo(client_bind_ai_lst);
6701 return STATE_MACHINE_FAILED;
6702 }
6703
6704
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 333247 times.
333250 if (ctx->non_blocking)
6705
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 vio_set_blocking_flag(net->vio, !ctx->non_blocking);
6706
6707
3/8
✓ Branch 0 taken 333238 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 333248 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 333248 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
333250 DBUG_PRINT("info", ("Connect socket"));
6708
6709
3/4
✓ Branch 0 taken 333245 times.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 333245 times.
333248 if (mysql->options.extension && mysql->options.extension->retry_count)
6710 my_net_set_retry_count(net, mysql->options.extension->retry_count);
6711
6712 333248 status = vio_socket_connect(
6713 333242 net->vio, t_res->ai_addr, (socklen_t)t_res->ai_addrlen,
6714
1/2
✓ Branch 0 taken 333246 times.
✗ Branch 1 not taken.
333242 ctx->non_blocking, get_vio_connect_timeout(mysql), &connect_done);
6715 /*
6716 Here we rely on vio_socket_connect() to return success only if
6717 the connect attempt was really successful. Otherwise we would
6718 stop trying another address, believing we were successful.
6719 */
6720
2/2
✓ Branch 0 taken 80596 times.
✓ Branch 1 taken 252650 times.
333246 if (!status) break;
6721
6722 /*
6723 Save either the socket error status or the error code of
6724 the failed vio_connection operation. It is necessary to
6725 avoid having it overwritten by later operations.
6726 */
6727 252650 saved_error = socket_errno;
6728
6729
3/8
✓ Branch 0 taken 252650 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 252650 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 252650 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
252650 DBUG_PRINT("info", ("No success, try next address."));
6730 }
6731
3/8
✓ Branch 0 taken 333246 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 333247 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 333247 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
333254 DBUG_PRINT("info",
6732 ("End of connect attempts, sock: %d status: %d error: %d",
6733 sock, status, saved_error));
6734
6735 333247 freeaddrinfo(res_lst);
6736
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 333231 times.
333251 if (client_bind_ai_lst) freeaddrinfo(client_bind_ai_lst);
6737
6738
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 333247 times.
333247 if (sock == INVALID_SOCKET) {
6739 set_mysql_extended_error(mysql, CR_IPSOCK_ERROR, unknown_sqlstate,
6740 ER_CLIENT(CR_IPSOCK_ERROR), saved_error);
6741 return STATE_MACHINE_FAILED;
6742 }
6743
6744
2/2
✓ Branch 0 taken 252654 times.
✓ Branch 1 taken 80593 times.
333247 if (status) {
6745
3/8
✓ Branch 0 taken 252654 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 252654 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 252654 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
252654 DBUG_PRINT("error",
6746 ("Got error %d on connect to '%s'", saved_error, host));
6747
1/2
✓ Branch 0 taken 252654 times.
✗ Branch 1 not taken.
252654 set_mysql_extended_error(mysql, CR_CONN_HOST_ERROR, unknown_sqlstate,
6748 ER_CLIENT(CR_CONN_HOST_ERROR), host, port,
6749 saved_error);
6750 252654 return STATE_MACHINE_FAILED;
6751 }
6752 }
6753
6754
2/2
✓ Branch 0 taken 383188 times.
✓ Branch 1 taken 2 times.
383190 ctx->state_function = connect_done ? csm_complete_connect : csm_wait_connect;
6755 383190 ctx->host = host;
6756 383190 ctx->user = user;
6757 383190 ctx->passwd = passwd;
6758 383190 ctx->db = db;
6759 383190 ctx->port = port;
6760 383190 ctx->unix_socket = unix_socket;
6761 383190 ctx->client_flag = client_flag;
6762 383190 return STATE_MACHINE_CONTINUE;
6763 2049844 }
6764
6765 /**
6766 Wait for async connect attempt to complete.
6767 */
6768 2 static mysql_state_machine_status csm_wait_connect(mysql_async_connect *ctx) {
6769 2 NET *net = &(ctx->mysql->net);
6770 2 MYSQL_VIO vio = net->vio;
6771 2 int timeout_ms = 1; // this is 1ms: the smallest non-zero timeout we can use
6772 int ret;
6773
6774
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 DBUG_TRACE;
6775
6776
3/14
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
2 DBUG_PRINT(
6777 "enter",
6778 ("host: %s db: %s user: %s (client)", ctx->host ? ctx->host : "(Null)",
6779 ctx->db ? ctx->db : "(Null)", ctx->user ? ctx->user : "(Null)"));
6780
6781
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!net->vio) {
6782 DBUG_PRINT("error", ("Unknown protocol %d", ctx->mysql->options.protocol));
6783 set_mysql_error(ctx->mysql, CR_CONN_UNKNOW_PROTOCOL, unknown_sqlstate);
6784 return STATE_MACHINE_FAILED;
6785 }
6786
6787 /*
6788 The connect() is in progress. The vio_io_wait() with the smallest non-zero
6789 timeout possible can be used to peek if connect() completed.
6790
6791 If vio_io_wait() returns 0,
6792 the socket never became writable or there is timeout and we'll return
6793 to caller.
6794 Otherwise, if vio_io_wait() returns 1, then one of two conditions
6795 exist:
6796
6797 1. An error occurred. Use getsockopt() to check for this.
6798 2. The connection was set up successfully: getsockopt() will
6799 return 0 as an error.
6800 */
6801
6802
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 int io_wait_ret = vio_io_wait(vio, VIO_IO_EVENT_CONNECT, timeout_ms);
6803
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (io_wait_ret == 0) return STATE_MACHINE_WOULD_BLOCK;
6804
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (io_wait_ret == -1) return STATE_MACHINE_FAILED;
6805
6806 int error;
6807 2 IF_WIN(int, socklen_t) optlen = sizeof(error);
6808 2 IF_WIN(char, void) *optval = (IF_WIN(char, void) *)&error;
6809
6810 /*
6811 At this point, we know that something happened on the socket.
6812 But this does not means that everything is alright. The connect
6813 might have failed. We need to retrieve the error code from the
6814 socket layer. We must return success only if we are sure that
6815 it was really a success. Otherwise we might prevent the caller
6816 from trying another address to connect to.
6817 */
6818
3/8
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2 DBUG_PRINT("info", ("Connect to '%s' completed", ctx->host));
6819 2 ctx->state_function = csm_complete_connect;
6820
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 if (!(ret = mysql_socket_getsockopt(vio->mysql_socket, SOL_SOCKET, SO_ERROR,
6821 optval, &optlen))) {
6822 #ifdef _WIN32
6823 WSASetLastError(error);
6824 #else
6825 2 errno = error;
6826 #endif
6827
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (error != 0) {
6828 DBUG_PRINT("error",
6829 ("Got error %d on connect to '%s'", error, ctx->host));
6830 set_mysql_extended_error(ctx->mysql, CR_CONN_HOST_ERROR, unknown_sqlstate,
6831 ER_CLIENT(CR_CONN_HOST_ERROR), ctx->host,
6832 ctx->port, error);
6833 return STATE_MACHINE_FAILED;
6834 }
6835 }
6836 2 return STATE_MACHINE_CONTINUE;
6837 2 }
6838
6839 /**
6840 Complete the connection itself, setting options on the now-connected socket.
6841 */
6842 383206 static mysql_state_machine_status csm_complete_connect(
6843 mysql_async_connect *ctx) {
6844
1/2
✓ Branch 0 taken 383473 times.
✗ Branch 1 not taken.
383206 DBUG_TRACE;
6845 383473 MYSQL *mysql = ctx->mysql;
6846 383473 NET *net = &mysql->net;
6847
3/8
✓ Branch 0 taken 383453 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 383440 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 383440 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
383473 DBUG_PRINT("info", ("net->vio: %p", net->vio));
6848
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 383321 times.
383325 if (!net->vio) {
6849
3/8
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
4 DBUG_PRINT("error", ("Unknow protocol %d ", mysql->options.protocol));
6850
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 set_mysql_error(mysql, CR_CONN_UNKNOW_PROTOCOL, unknown_sqlstate);
6851 4 return STATE_MACHINE_FAILED;
6852 }
6853
6854
2/4
✓ Branch 0 taken 383347 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 383347 times.
383321 if (my_net_init(net, net->vio)) {
6855 vio_delete(net->vio);
6856 net->vio = nullptr;
6857 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
6858 return STATE_MACHINE_FAILED;
6859 }
6860
1/2
✓ Branch 0 taken 383409 times.
✗ Branch 1 not taken.
383347 vio_keepalive(net->vio, true);
6861
6862 /* If user set read_timeout, let it override the default */
6863
2/2
✓ Branch 0 taken 25962 times.
✓ Branch 1 taken 357447 times.
383409 if (mysql->options.read_timeout)
6864
1/2
✓ Branch 0 taken 25962 times.
✗ Branch 1 not taken.
25962 my_net_set_read_timeout(net, mysql->options.read_timeout);
6865
6866 /* If user set write_timeout, let it override the default */
6867
2/2
✓ Branch 0 taken 482 times.
✓ Branch 1 taken 382927 times.
383409 if (mysql->options.write_timeout)
6868
1/2
✓ Branch 0 taken 482 times.
✗ Branch 1 not taken.
482 my_net_set_write_timeout(net, mysql->options.write_timeout);
6869
6870 /* If user set retry_count, let it override the default */
6871
3/4
✓ Branch 0 taken 383312 times.
✓ Branch 1 taken 97 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 383312 times.
383409 if (mysql->options.extension && mysql->options.extension->retry_count)
6872 my_net_set_retry_count(net, mysql->options.extension->retry_count);
6873
6874
2/2
✓ Branch 0 taken 8626 times.
✓ Branch 1 taken 374732 times.
383358 if (mysql->options.max_allowed_packet)
6875 8626 net->max_packet_size = mysql->options.max_allowed_packet;
6876
6877
3/8
✓ Branch 0 taken 371822 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 371802 times.
✓ Branch 5 taken 20 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
371822 MYSQL_TRACE(CONNECTED, mysql, ());
6878
2/10
✓ Branch 0 taken 371816 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 371816 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
371802 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_INIT_PACKET);
6879
6880 /* Get version info */
6881 383352 mysql->protocol_version = PROTOCOL_VERSION; /* Assume this */
6882
6/6
✓ Branch 0 taken 148145 times.
✓ Branch 1 taken 235207 times.
✓ Branch 2 taken 148104 times.
✓ Branch 3 taken 41 times.
✓ Branch 4 taken 34 times.
✓ Branch 5 taken 383222 times.
531360 if (mysql->options.connect_timeout && !ctx->non_blocking &&
6883
3/4
✓ Branch 0 taken 148008 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 147974 times.
148104 (vio_io_wait(net->vio, VIO_IO_EVENT_READ,
6884 get_vio_connect_timeout(mysql)) < 1)) {
6885
1/2
✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
34 set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
6886 ER_CLIENT(CR_SERVER_LOST_EXTENDED),
6887 "waiting for initial communication packet",
6888 34 socket_errno);
6889 34 return STATE_MACHINE_FAILED;
6890 }
6891 383222 ctx->state_function = csm_read_greeting;
6892 383222 return STATE_MACHINE_CONTINUE;
6893 383260 }
6894
6895 /**
6896 Read the greeting from the server that is read the first packet
6897 */
6898 400655 static mysql_state_machine_status csm_read_greeting(mysql_async_connect *ctx) {
6899
1/2
✓ Branch 0 taken 400830 times.
✗ Branch 1 not taken.
400655 DBUG_TRACE;
6900 400830 MYSQL *mysql = ctx->mysql;
6901
3/8
✓ Branch 0 taken 400821 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 400819 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 400819 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
400830 DBUG_PRINT("info", ("Read first packet."));
6902
6903
2/2
✓ Branch 0 taken 383365 times.
✓ Branch 1 taken 17440 times.
400805 if (!ctx->non_blocking)
6904
1/2
✓ Branch 0 taken 383338 times.
✗ Branch 1 not taken.
383365 ctx->pkt_length = cli_safe_read(mysql, nullptr);
6905 else {
6906
3/4
✓ Branch 0 taken 17440 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17390 times.
✓ Branch 3 taken 50 times.
17440 if (cli_safe_read_nonblocking(mysql, nullptr, &ctx->pkt_length) ==
6907 NET_ASYNC_NOT_READY) {
6908 17390 return STATE_MACHINE_WOULD_BLOCK;
6909 }
6910 }
6911
2/2
✓ Branch 0 taken 427 times.
✓ Branch 1 taken 382961 times.
383388 if (ctx->pkt_length == packet_error) {
6912
2/2
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 327 times.
427 if (mysql->net.last_errno == CR_SERVER_LOST)
6913
1/2
✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
100 set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
6914 ER_CLIENT(CR_SERVER_LOST_EXTENDED),
6915 "reading initial communication packet",
6916 100 socket_errno);
6917 427 return STATE_MACHINE_FAILED;
6918 }
6919 382961 ctx->state_function = csm_parse_handshake;
6920 382961 return STATE_MACHINE_CONTINUE;
6921 400778 }
6922
6923 /**
6924 Parse the handshake from the server.
6925 */
6926 382958 static mysql_state_machine_status csm_parse_handshake(
6927 mysql_async_connect *ctx) {
6928
1/2
✓ Branch 0 taken 383036 times.
✗ Branch 1 not taken.
382958 DBUG_TRACE;
6929 383036 MYSQL *mysql = ctx->mysql;
6930 383036 NET *net = &mysql->net;
6931 383036 int pkt_length = ctx->pkt_length;
6932 383036 int pkt_scramble_len = 0;
6933 char *end, *server_version_end, *pkt_end;
6934 383036 pkt_end = (char *)net->read_pos + pkt_length;
6935 /* Check if version of protocol matches current one */
6936 383036 mysql->protocol_version = net->read_pos[0];
6937
1/2
✓ Branch 0 taken 383028 times.
✗ Branch 1 not taken.
383036 DBUG_DUMP("packet", (uchar *)net->read_pos, 10);
6938
3/8
✓ Branch 0 taken 383021 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 382986 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 382986 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
383028 DBUG_PRINT("info", ("mysql protocol version %d, server=%d", PROTOCOL_VERSION,
6939 mysql->protocol_version));
6940
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 382996 times.
382997 if (mysql->protocol_version != PROTOCOL_VERSION) {
6941
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 set_mysql_extended_error(mysql, CR_VERSION_ERROR, unknown_sqlstate,
6942 ER_CLIENT(CR_VERSION_ERROR),
6943 mysql->protocol_version, PROTOCOL_VERSION);
6944 1 return STATE_MACHINE_FAILED;
6945 }
6946 382996 server_version_end = end = strend((char *)net->read_pos + 1);
6947 383013 mysql->thread_id = uint4korr((uchar *)end + 1);
6948 383005 end += 5;
6949 /*
6950 Scramble is split into two parts because old clients do not understand
6951 long scrambles; here goes the first part.
6952 */
6953 383005 ctx->scramble_data = end;
6954 383005 ctx->scramble_data_len = AUTH_PLUGIN_DATA_PART_1_LENGTH + 1;
6955 383005 ctx->scramble_plugin = nullptr;
6956 383005 end += ctx->scramble_data_len;
6957
6958
1/2
✓ Branch 0 taken 383006 times.
✗ Branch 1 not taken.
383005 if (pkt_end >= end + 1) mysql->server_capabilities = uint2korr((uchar *)end);
6959
1/2
✓ Branch 0 taken 383023 times.
✗ Branch 1 not taken.
383016 if (pkt_end >= end + 18) {
6960 /* New protocol with 16 bytes to describe server characteristics */
6961 383023 mysql->server_language = end[2];
6962 383023 mysql->server_status = uint2korr((uchar *)end + 3);
6963 383009 mysql->server_capabilities |= uint2korr((uchar *)end + 5) << 16;
6964 383011 pkt_scramble_len = end[7];
6965
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 383011 times.
383011 if (pkt_scramble_len < 0) {
6966 set_mysql_error(mysql, CR_MALFORMED_PACKET,
6967 unknown_sqlstate); /* purecov: inspected */
6968 return STATE_MACHINE_FAILED;
6969 }
6970 }
6971 383004 end += 18;
6972
6973
2/4
✓ Branch 0 taken 382878 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 382878 times.
383004 if (mysql_init_character_set(mysql)) return STATE_MACHINE_FAILED;
6974
6975 /* Save connection information */
6976 80135 if (!my_multi_malloc(
6977 key_memory_MYSQL, MYF(0), &mysql->host_info,
6978 382878 (uint)strlen(ctx->host_info) + 1, &mysql->host,
6979
1/2
✓ Branch 0 taken 383029 times.
✗ Branch 1 not taken.
382878 (uint)strlen(ctx->host) + 1, &mysql->unix_socket,
6980 302743 ctx->unix_socket ? (uint)strlen(ctx->unix_socket) + 1 : (uint)1,
6981 &mysql->server_version,
6982
2/2
✓ Branch 0 taken 302743 times.
✓ Branch 1 taken 80135 times.
382878 (uint)(server_version_end - (char *)net->read_pos + 1), NullS) ||
6983
5/8
✓ Branch 0 taken 383012 times.
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 383020 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 383025 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 383037 times.
766054 !(mysql->user = my_strdup(key_memory_MYSQL, ctx->user, MYF(0))) ||
6984
3/4
✓ Branch 0 taken 383025 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 383017 times.
383025 !(mysql->passwd = my_strdup(key_memory_MYSQL, ctx->passwd, MYF(0)))) {
6985 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
6986 return STATE_MACHINE_FAILED;
6987 }
6988 383037 my_stpcpy(mysql->host_info, ctx->host_info);
6989 382885 my_stpcpy(mysql->host, ctx->host);
6990
2/2
✓ Branch 0 taken 302744 times.
✓ Branch 1 taken 80200 times.
382944 if (ctx->unix_socket)
6991 302744 my_stpcpy(mysql->unix_socket, ctx->unix_socket);
6992 else
6993 80200 mysql->unix_socket = nullptr;
6994 382965 my_stpcpy(mysql->server_version, (char *)net->read_pos + 1);
6995 383001 mysql->port = ctx->port;
6996
6997
2/2
✓ Branch 0 taken 382992 times.
✓ Branch 1 taken 9 times.
383001 if (pkt_end >= end + SCRAMBLE_LENGTH - AUTH_PLUGIN_DATA_PART_1_LENGTH + 1)
6998
6999 {
7000 /*
7001 move the first scramble part - directly in the NET buffer -
7002 to get a full continuous scramble. We've read all the header,
7003 and can overwrite it now.
7004 */
7005 382992 memmove(end - AUTH_PLUGIN_DATA_PART_1_LENGTH, ctx->scramble_data,
7006 AUTH_PLUGIN_DATA_PART_1_LENGTH);
7007 382992 ctx->scramble_data = end - AUTH_PLUGIN_DATA_PART_1_LENGTH;
7008
1/2
✓ Branch 0 taken 382992 times.
✗ Branch 1 not taken.
382992 if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH) {
7009 382992 ctx->scramble_data_len = pkt_scramble_len;
7010 382992 ctx->scramble_plugin = ctx->scramble_data + ctx->scramble_data_len;
7011 /*
7012 There is a possibility that we did not get a correct plugin name
7013 for some reason. For example, the packet was malformed and some
7014 of the fields had incorrect values. In such cases, we keep the
7015 plugin name empty so that the default authentication plugin
7016 gets used later on. Since we don't really know the plugin for which
7017 the scramble_data was prepared, we can discard it and set it's length
7018 to 0.
7019 */
7020
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 382992 times.
382992 if (ctx->scramble_data + ctx->scramble_data_len > pkt_end) {
7021 ctx->scramble_data = nullptr;
7022 ctx->scramble_data_len = 0;
7023 ctx->scramble_plugin = const_cast<char *>("");
7024 }
7025 } else {
7026 ctx->scramble_data_len = (int)(pkt_end - ctx->scramble_data);
7027 ctx->scramble_plugin = caching_sha2_password_plugin_name;
7028 }
7029 } else {
7030
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
9 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
7031 return STATE_MACHINE_FAILED;
7032 }
7033 382992 ctx->state_function = csm_establish_ssl;
7034 382992 return STATE_MACHINE_CONTINUE;
7035 382993 }
7036
7037 /**
7038 Establish SSL if needed.
7039 */
7040 400321 static mysql_state_machine_status csm_establish_ssl(mysql_async_connect *ctx) {
7041
1/2
✓ Branch 0 taken 400419 times.
✗ Branch 1 not taken.
400321 DBUG_TRACE;
7042 400419 MYSQL *mysql = ctx->mysql;
7043 /* This check happens to work for both sync and async. */
7044
2/2
✓ Branch 0 taken 383032 times.
✓ Branch 1 taken 17387 times.
400419 if (ctx->ssl_state == SSL_NONE) {
7045
3/8
✓ Branch 0 taken 371514 times.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 371520 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
371524 MYSQL_TRACE(INIT_PACKET_RECEIVED, mysql,
7046 (ctx->pkt_length, mysql->net.read_pos));
7047
3/10
✓ Branch 0 taken 371512 times.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 371512 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
371520 MYSQL_TRACE_STAGE(mysql, AUTHENTICATE);
7048
7049 #if defined(_WIN32)
7050 if ((mysql->options.extension &&
7051 mysql->options.extension->ssl_mode <= SSL_MODE_PREFERRED) &&
7052 (mysql->options.protocol == MYSQL_PROTOCOL_MEMORY ||
7053 mysql->options.protocol == MYSQL_PROTOCOL_PIPE)) {
7054 mysql->options.extension->ssl_mode = SSL_MODE_DISABLED;
7055 }
7056 #endif
7057 /* try and bring up SSL if possible */
7058 383020 cli_calculate_client_flag(mysql, ctx->db, ctx->client_flag);
7059
7060 /*
7061 Allocate separate buffer for scramble data if we are going
7062 to attempt TLS connection. This would prevent a possible
7063 overwrite through my_net_write.
7064 */
7065
2/4
✓ Branch 0 taken 382993 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 383001 times.
✗ Branch 3 not taken.
382985 if (ctx->scramble_data_len && mysql->options.extension &&
7066
2/2
✓ Branch 0 taken 37083 times.
✓ Branch 1 taken 345918 times.
383001 mysql->options.extension->ssl_mode != SSL_MODE_DISABLED) {
7067 37082 if (!(ctx->scramble_buffer =
7068
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37082 times.
37082 (char *)my_malloc(key_memory_MYSQL_HANDSHAKE,
7069
1/2
✓ Branch 0 taken 37082 times.
✗ Branch 1 not taken.
37083 ctx->scramble_data_len, MYF(MY_WME)))) {
7070 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
7071 return STATE_MACHINE_FAILED;
7072 }
7073 37082 ctx->scramble_buffer_allocated = true;
7074 37082 memcpy(ctx->scramble_buffer, ctx->scramble_data, ctx->scramble_data_len);
7075 } else {
7076 345902 ctx->scramble_buffer = ctx->scramble_data;
7077 }
7078 }
7079
2/2
✓ Branch 0 taken 17438 times.
✓ Branch 1 taken 382933 times.
400371 if (ctx->non_blocking) {
7080 int ret;
7081
3/4
✓ Branch 0 taken 17438 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17389 times.
✓ Branch 3 taken 49 times.
17438 if (cli_establish_ssl_nonblocking(mysql, &ret) == NET_ASYNC_NOT_READY) {
7082 17389 return STATE_MACHINE_WOULD_BLOCK;
7083 }
7084
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 49 times.
49 if (ret) {
7085 return STATE_MACHINE_FAILED;
7086 }
7087 } else {
7088
3/4
✓ Branch 0 taken 382850 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 132 times.
✓ Branch 3 taken 382718 times.
382933 if (cli_establish_ssl(mysql)) {
7089 132 return STATE_MACHINE_FAILED;
7090 }
7091 }
7092
7093 382767 ctx->state_function = csm_authenticate;
7094 382767 return STATE_MACHINE_CONTINUE;
7095 400288 }
7096
7097 /**
7098 Invoke the authentication client plugin API to send the authentication
7099 data to the server
7100 */
7101 395571 static mysql_state_machine_status csm_authenticate(mysql_async_connect *ctx) {
7102
1/2
✓ Branch 0 taken 395627 times.
✗ Branch 1 not taken.
395571 DBUG_TRACE;
7103 395627 MYSQL *mysql = ctx->mysql;
7104
2/2
✓ Branch 0 taken 12776 times.
✓ Branch 1 taken 382851 times.
395627 if (ctx->non_blocking) {
7105 25552 mysql_state_machine_status status = run_plugin_auth_nonblocking(
7106
1/2
✓ Branch 0 taken 12776 times.
✗ Branch 1 not taken.
12776 ctx->mysql, ctx->scramble_data, ctx->scramble_data_len,
7107 ctx->scramble_plugin, ctx->db);
7108
2/2
✓ Branch 0 taken 12736 times.
✓ Branch 1 taken 40 times.
12776 if (status != STATE_MACHINE_DONE) {
7109 12736 return status;
7110 }
7111 } else {
7112
3/4
✓ Branch 0 taken 382748 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2537 times.
✓ Branch 3 taken 380211 times.
382851 if (run_plugin_auth(mysql, ctx->scramble_buffer, ctx->scramble_data_len,
7113 ctx->scramble_plugin, ctx->db)) {
7114 2537 return STATE_MACHINE_FAILED;
7115 }
7116 }
7117
7118
2/2
✓ Branch 0 taken 35511 times.
✓ Branch 1 taken 344740 times.
380251 if (ctx->scramble_buffer_allocated) {
7119 35511 ctx->scramble_buffer_allocated = false;
7120
1/2
✓ Branch 0 taken 35511 times.
✗ Branch 1 not taken.
35511 my_free(ctx->scramble_buffer);
7121 35511 ctx->scramble_buffer = nullptr;
7122 }
7123
7124 380251 ctx->state_function = csm_prep_select_database;
7125 380251 return STATE_MACHINE_CONTINUE;
7126 395524 }
7127
7128 /**
7129 Authenticated, set initial database if specified
7130 */
7131 380247 static mysql_state_machine_status csm_prep_select_database(
7132 mysql_async_connect *ctx) {
7133
1/2
✓ Branch 0 taken 380356 times.
✗ Branch 1 not taken.
380247 DBUG_TRACE;
7134 380356 MYSQL *mysql = ctx->mysql;
7135 380356 NET *net = &mysql->net;
7136
7137
2/10
✓ Branch 0 taken 369163 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 369163 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
369162 MYSQL_TRACE_STAGE(mysql, READY_FOR_COMMAND);
7138
7139 /* We will use compression */
7140
2/2
✓ Branch 0 taken 380226 times.
✓ Branch 1 taken 131 times.
380357 if ((mysql->client_flag & CLIENT_COMPRESS) ||
7141
2/2
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 380153 times.
380226 (mysql->client_flag & CLIENT_ZSTD_COMPRESSION_ALGORITHM)) {
7142 204 net->compress = true;
7143 uint compress_level;
7144 204 enum enum_compression_algorithm algorithm =
7145
2/2
✓ Branch 0 taken 118 times.
✓ Branch 1 taken 86 times.
204 mysql->client_flag & CLIENT_COMPRESS ? MYSQL_ZLIB : MYSQL_ZSTD;
7146
1/2
✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
204 if (mysql->options.extension &&
7147
2/2
✓ Branch 0 taken 197 times.
✓ Branch 1 taken 7 times.
204 mysql->options.extension->zstd_compression_level)
7148 197 compress_level = mysql->options.extension->zstd_compression_level;
7149 else
7150
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 compress_level = mysql_default_compression_level(algorithm);
7151 #ifndef MYSQL_SERVER
7152 135 NET_EXTENSION *ext = NET_EXTENSION_PTR(net);
7153
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 135 times.
135 assert(ext != nullptr);
7154
1/2
✓ Branch 0 taken 135 times.
✗ Branch 1 not taken.
135 mysql_compress_context_init(&ext->compress_ctx, algorithm, compress_level);
7155 #else
7156 69 NET_SERVER *server_ext = static_cast<NET_SERVER *>(net->extension);
7157
1/2
✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
69 if (server_ext == nullptr) {
7158 69 server_ext =
7159
1/4
✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
69 static_cast<NET_SERVER *>(MYSQL_EXTENSION_PTR(mysql)->server_extn);
7160 69 net->extension = server_ext;
7161 }
7162
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 69 times.
69 assert(server_ext != nullptr);
7163
1/2
✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
69 mysql_compress_context_init(&server_ext->compress_ctx, algorithm,
7164 compress_level);
7165 #endif
7166 }
7167 #ifdef CHECK_LICENSE
7168 if (check_license(mysql)) return STATE_MACHINE_FAILED;
7169 #endif
7170
7171 #ifdef MYSQL_SERVER
7172 11194 return STATE_MACHINE_DONE;
7173 #else
7174 369163 ctx->state_function = csm_prep_init_commands;
7175 #endif
7176
7177 369132 return STATE_MACHINE_CONTINUE;
7178 380357 }
7179
7180 #ifndef MYSQL_SERVER
7181 /**
7182 Prepare to send a sequence of init commands.
7183 */
7184 369094 static mysql_state_machine_status csm_prep_init_commands(
7185 mysql_async_connect *ctx) {
7186
1/2
✓ Branch 0 taken 369159 times.
✗ Branch 1 not taken.
369094 DBUG_TRACE;
7187 369159 MYSQL *mysql = ctx->mysql;
7188
2/2
✓ Branch 0 taken 369153 times.
✓ Branch 1 taken 6 times.
369159 if (!mysql->options.init_commands) {
7189 369153 return STATE_MACHINE_DONE;
7190 }
7191
7192 6 ctx->saved_reconnect = mysql->reconnect;
7193 6 mysql->reconnect = false;
7194
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
6 ctx->current_init_command = mysql->options.init_commands->begin();
7195
7196 3 ctx->state_function = csm_send_one_init_command;
7197 3 return STATE_MACHINE_CONTINUE;
7198 369156 }
7199
7200 /**
7201 Send an init command. This is called once per init command until
7202 they've all been run (or a failure occurs).
7203 */
7204 3 static mysql_state_machine_status csm_send_one_init_command(
7205 mysql_async_connect *ctx) {
7206
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 DBUG_TRACE;
7207 3 MYSQL *mysql = ctx->mysql;
7208
7209
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (mysql_real_query(mysql, *ctx->current_init_command,
7210
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 (ulong)strlen(*ctx->current_init_command)))
7211 return STATE_MACHINE_FAILED;
7212 int status;
7213 do {
7214
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
5 if (mysql->fields) {
7215 MYSQL_RES *res;
7216
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 if (!(res = cli_use_result(mysql))) return STATE_MACHINE_FAILED;
7217
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 mysql_free_result(res);
7218 }
7219
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
5 if ((status = mysql_next_result(mysql)) > 0) return STATE_MACHINE_FAILED;
7220
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
5 } while (status == 0);
7221
7222 3 ++ctx->current_init_command;
7223
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 if (ctx->current_init_command < mysql->options.init_commands->end()) {
7224 return STATE_MACHINE_CONTINUE;
7225 }
7226 3 mysql->reconnect = ctx->saved_reconnect;
7227
3/8
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
3 DBUG_PRINT("exit", ("Mysql handler: %p", mysql));
7228 3 return STATE_MACHINE_DONE;
7229 3 }
7230 #endif
7231
7232 1656650 bool mysql_reconnect(MYSQL *mysql) {
7233 MYSQL tmp_mysql;
7234
1/2
✓ Branch 0 taken 1656650 times.
✗ Branch 1 not taken.
1656650 DBUG_TRACE;
7235
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1656650 times.
1656650 assert(mysql);
7236
3/8
✓ Branch 0 taken 1656650 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1656650 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1656650 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1656650 DBUG_PRINT("enter", ("mysql->reconnect: %d", mysql->reconnect));
7237
7238
3/4
✓ Branch 0 taken 1656386 times.
✓ Branch 1 taken 264 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1656386 times.
1656650 if ((mysql->server_status & SERVER_STATUS_IN_TRANS) || !mysql->host_info) {
7239 /* Allow reconnect next time */
7240 264 mysql->server_status &= ~SERVER_STATUS_IN_TRANS;
7241
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 252 times.
264 if (mysql->net.last_errno == 0)
7242
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 set_mysql_error(mysql, CR_SERVER_LOST, unknown_sqlstate);
7243 264 return true;
7244 }
7245
1/2
✓ Branch 0 taken 1656386 times.
✗ Branch 1 not taken.
1656386 mysql_init(&tmp_mysql);
7246
1/2
✓ Branch 0 taken 1656386 times.
✗ Branch 1 not taken.
1656386 mysql_close_free_options(&tmp_mysql);
7247 1656386 tmp_mysql.options = mysql->options;
7248 1656386 tmp_mysql.options.my_cnf_file = tmp_mysql.options.my_cnf_group = nullptr;
7249 #ifdef MYSQL_SERVER
7250
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
1154 NET_SERVER *server_extn = MYSQL_EXTENSION_PTR(&tmp_mysql)->server_extn =
7251
2/6
✓ Branch 0 taken 1154 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1154 times.
✗ Branch 5 not taken.
1154 MYSQL_EXTENSION_PTR(mysql)->server_extn;
7252
1/4
✓ Branch 0 taken 1154 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1154 MYSQL_EXTENSION_PTR(mysql)->server_extn = nullptr;
7253 #endif
7254
2/2
✓ Branch 0 taken 1644323 times.
✓ Branch 1 taken 12063 times.
1656386 if (!mysql_real_connect(&tmp_mysql, mysql->host, mysql->user, mysql->passwd,
7255 1656386 mysql->db, mysql->port, mysql->unix_socket,
7256
1/2
✓ Branch 0 taken 1656386 times.
✗ Branch 1 not taken.
1656386 mysql->client_flag | CLIENT_REMEMBER_OPTIONS)) {
7257 #ifdef MYSQL_SERVER
7258
1/4
✓ Branch 0 taken 821 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
821 MYSQL_EXTENSION_PTR(mysql)->server_extn = server_extn;
7259 #endif
7260 1644323 memset(&tmp_mysql.options, 0, sizeof(tmp_mysql.options));
7261 1644323 mysql->net.last_errno = tmp_mysql.net.last_errno;
7262 1644323 my_stpcpy(mysql->net.last_error, tmp_mysql.net.last_error);
7263 1644323 my_stpcpy(mysql->net.sqlstate, tmp_mysql.net.sqlstate);
7264 1644323 return true;
7265 }
7266
2/4
✓ Branch 0 taken 12063 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 12063 times.
12063 if (mysql_set_character_set(&tmp_mysql, mysql->charset->csname)) {
7267 DBUG_PRINT("error", ("mysql_set_character_set() failed"));
7268 #ifdef MYSQL_SERVER
7269 MYSQL_EXTENSION_PTR(mysql)->server_extn = server_extn;
7270 #endif
7271 memset(&tmp_mysql.options, 0, sizeof(tmp_mysql.options));
7272 mysql_close(&tmp_mysql);
7273 mysql->net.last_errno = tmp_mysql.net.last_errno;
7274 my_stpcpy(mysql->net.last_error, tmp_mysql.net.last_error);
7275 my_stpcpy(mysql->net.sqlstate, tmp_mysql.net.sqlstate);
7276 return true;
7277 }
7278
7279
3/8
✓ Branch 0 taken 12063 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12063 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 12063 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
12063 DBUG_PRINT("info", ("reconnect succeded"));
7280 12063 tmp_mysql.reconnect = true;
7281 12063 tmp_mysql.free_me = mysql->free_me;
7282
7283 /* Move prepared statements (if any) over to the new mysql object */
7284 12063 tmp_mysql.stmts = mysql->stmts;
7285 12063 mysql->stmts = nullptr;
7286
7287 /* Don't free options as these are now used in tmp_mysql */
7288 12063 memset(&mysql->options, 0, sizeof(mysql->options));
7289 12063 mysql->free_me = false;
7290
1/2
✓ Branch 0 taken 12063 times.
✗ Branch 1 not taken.
12063 mysql_close(mysql);
7291 12063 *mysql = std::move(tmp_mysql);
7292
1/2
✓ Branch 0 taken 12063 times.
✗ Branch 1 not taken.
12063 net_clear(&mysql->net, true);
7293 12063 mysql->affected_rows = ~(my_ulonglong)0;
7294 12063 return false;
7295 1656650 }
7296
7297 /**
7298 Open a new replication stream.
7299
7300 Compose and send COM_BINLOG_DUMP[_GTID] command
7301 using information in the MYSQL_RPL structure.
7302
7303 Caller must set the following MYSQL_RPL's slots:
7304 file_name_length, file_name, start_positions, server_id, flags
7305 and in case of MYSQL_RPL_GTID: gtid_set_size, gtid_set
7306 or fix_gtid_set/fix_gtid_set_arg which is used to compose command packet.
7307
7308 Note: we treat NULL rpl->file_name as an empty string.
7309 If rpl->file_name_length is 0, strlen(rpl->file_name)
7310 will be called to set it.
7311 If rpl->fix_gtid_set is not NULL it will be called to fill
7312 packet gtid set data (rpl->gtid_set is ignored).
7313
7314 @param mysql Connection handle.
7315 @param rpl Replication stream information.
7316
7317 @retval -1 Error.
7318 @retval 0 Success.
7319 */
7320 7597 int STDCALL mysql_binlog_open(MYSQL *mysql, MYSQL_RPL *rpl) {
7321
1/2
✓ Branch 0 taken 7597 times.
✗ Branch 1 not taken.
7597 DBUG_TRACE;
7322
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7597 times.
7597 assert(mysql);
7323
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7597 times.
7597 assert(rpl);
7324
7325 enum enum_server_command command;
7326 7597 uchar *command_buffer = nullptr;
7327 7597 size_t command_size = 0;
7328
7329 /*
7330 No need to check mysql->net.vio here as
7331 it'll be checked in the simple_command().
7332 */
7333
7334
2/2
✓ Branch 0 taken 2230 times.
✓ Branch 1 taken 5367 times.
7597 if (!rpl->file_name) {
7335 2230 rpl->file_name = const_cast<char *>("");
7336 2230 rpl->file_name_length = 0;
7337
1/2
✓ Branch 0 taken 5367 times.
✗ Branch 1 not taken.
5367 } else if (rpl->file_name_length == 0)
7338 5367 rpl->file_name_length = strlen(rpl->file_name);
7339
7340
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7597 times.
7597 if (rpl->file_name_length > UINT_MAX) {
7341 set_mysql_error(mysql, CR_FILE_NAME_TOO_LONG, unknown_sqlstate);
7342 return -1;
7343 }
7344
7345
2/2
✓ Branch 0 taken 2235 times.
✓ Branch 1 taken 5362 times.
7597 if (rpl->flags & MYSQL_RPL_GTID) {
7346 2235 command = COM_BINLOG_DUMP_GTID;
7347
7348 #define GTID_ENCODED_DATA_SIZE 8
7349
7350 4470 size_t alloc_size = rpl->file_name_length + ::BINLOG_FLAGS_INFO_SIZE +
7351 ::BINLOG_SERVER_ID_INFO_SIZE +
7352 ::BINLOG_NAME_SIZE_INFO_SIZE + ::BINLOG_POS_INFO_SIZE +
7353 2235 ::BINLOG_DATA_SIZE_INFO_SIZE +
7354
1/2
✓ Branch 0 taken 2235 times.
✗ Branch 1 not taken.
2235 (rpl->gtid_set_encoded_size ? rpl->gtid_set_encoded_size
7355 : GTID_ENCODED_DATA_SIZE) +
7356 1;
7357
7358
2/4
✓ Branch 0 taken 2235 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2235 times.
2235 if (!(command_buffer = (uchar *)my_malloc(PSI_NOT_INSTRUMENTED, alloc_size,
7359 MYF(MY_WME)))) {
7360 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
7361 return -1;
7362 }
7363
7364 2235 uchar *ptr = command_buffer;
7365
7366 2235 int2store(ptr, rpl->flags); // Note: we use low 16 bits
7367 2235 ptr += ::BINLOG_FLAGS_INFO_SIZE;
7368 2235 int4store(ptr, rpl->server_id);
7369 2235 ptr += ::BINLOG_SERVER_ID_INFO_SIZE;
7370 2235 int4store(ptr, static_cast<uint32>(rpl->file_name_length));
7371 2235 ptr += ::BINLOG_NAME_SIZE_INFO_SIZE;
7372 2235 memcpy(ptr, rpl->file_name, rpl->file_name_length);
7373 2235 ptr += rpl->file_name_length;
7374 2235 int8store(ptr, rpl->start_position);
7375 2235 ptr += ::BINLOG_POS_INFO_SIZE;
7376
1/2
✓ Branch 0 taken 2235 times.
✗ Branch 1 not taken.
2235 if (rpl->gtid_set_encoded_size) {
7377 2235 int4store(ptr, static_cast<uint32>(rpl->gtid_set_encoded_size));
7378 2235 ptr += ::BINLOG_DATA_SIZE_INFO_SIZE;
7379
1/2
✓ Branch 0 taken 2235 times.
✗ Branch 1 not taken.
2235 if (rpl->fix_gtid_set)
7380
1/2
✓ Branch 0 taken 2235 times.
✗ Branch 1 not taken.
2235 rpl->fix_gtid_set(rpl, ptr);
7381 else
7382 memcpy(ptr, rpl->gtid_set_arg, rpl->gtid_set_encoded_size);
7383 2235 ptr += rpl->gtid_set_encoded_size;
7384 } else {
7385 /* No GTID set data, store 0 as its length. */
7386 int4store(ptr, static_cast<uint32>(GTID_ENCODED_DATA_SIZE));
7387 ptr += ::BINLOG_DATA_SIZE_INFO_SIZE;
7388 int8store(ptr, static_cast<uint64>(0));
7389 ptr += GTID_ENCODED_DATA_SIZE;
7390 }
7391
7392 2235 command_size = ptr - command_buffer;
7393
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2235 times.
2235 assert(command_size == (alloc_size - 1));
7394 } else {
7395 5362 command = COM_BINLOG_DUMP;
7396 5362 size_t alloc_size = rpl->file_name_length + ::BINLOG_POS_OLD_INFO_SIZE +
7397 ::BINLOG_FLAGS_INFO_SIZE +
7398 ::BINLOG_SERVER_ID_INFO_SIZE + 1;
7399
7400
2/4
✓ Branch 0 taken 5362 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5362 times.
5362 if (!(command_buffer = (uchar *)my_malloc(PSI_NOT_INSTRUMENTED, alloc_size,
7401 MYF(MY_WME)))) {
7402 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
7403 return -1;
7404 }
7405
7406 5362 uchar *ptr = command_buffer;
7407
7408 /*
7409 COM_BINLOG_DUMP accepts only 4 bytes for the position, so
7410 we are forced to cast to uint32.
7411 */
7412 5362 int4store(ptr, (uint32)rpl->start_position);
7413 5362 ptr += ::BINLOG_POS_OLD_INFO_SIZE;
7414 5362 int2store(ptr, rpl->flags); // note: we use low 16 bits
7415 5362 ptr += ::BINLOG_FLAGS_INFO_SIZE;
7416 5362 int4store(ptr, rpl->server_id);
7417 5362 ptr += ::BINLOG_SERVER_ID_INFO_SIZE;
7418 5362 memcpy(ptr, rpl->file_name, rpl->file_name_length);
7419 5362 ptr += rpl->file_name_length;
7420
7421 5362 command_size = ptr - command_buffer;
7422
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5362 times.
5362 assert(command_size == (alloc_size - 1));
7423 }
7424
7425
3/8
✓ Branch 0 taken 7597 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7597 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 7597 times.
7597 if (simple_command(mysql, command, command_buffer, command_size, 1)) {
7426 my_free(command_buffer);
7427 return -1;
7428 }
7429
7430
1/2
✓ Branch 0 taken 7597 times.
✗ Branch 1 not taken.
7597 my_free(command_buffer);
7431
7432 7597 return 0;
7433 7597 }
7434
7435 /**
7436 Fetch one event from the server.
7437
7438 Read one packet and check its validity,
7439 set rpl->buffer and rpl->size accordingly.
7440
7441 @param mysql Connection handle.
7442 @param rpl Replication stream information.
7443
7444 @retval -1 Got error packet.
7445 @retval 0 Success.
7446 */
7447 1577345 int STDCALL mysql_binlog_fetch(MYSQL *mysql, MYSQL_RPL *rpl) {
7448
1/2
✓ Branch 0 taken 1577345 times.
✗ Branch 1 not taken.
1577345 DBUG_TRACE;
7449
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1577345 times.
1577345 assert(mysql);
7450
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1577345 times.
1577345 assert(rpl);
7451
7452 for (;;) {
7453 /* Read a packet from the server. */
7454
1/2
✓ Branch 0 taken 1577199 times.
✗ Branch 1 not taken.
1577345 ulong packet_len = cli_safe_read(mysql, nullptr);
7455
7456 1577199 NET *net = &mysql->net;
7457
7458 /* Check if error packet. */
7459
3/4
✓ Branch 0 taken 1570161 times.
✓ Branch 1 taken 7038 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1570161 times.
1577199 if (packet_len == packet_error || packet_len == 0) {
7460 7038 return -1;
7461 }
7462 /* Check if EOF packet. */
7463
3/4
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 1570049 times.
✓ Branch 2 taken 112 times.
✗ Branch 3 not taken.
1570161 else if (packet_len < 8 && net->read_pos[0] == 254) {
7464 112 rpl->size = 0;
7465 112 return 0;
7466 }
7467
7468 /* Normal packet. */
7469
2/2
✓ Branch 0 taken 14110 times.
✓ Branch 1 taken 1555939 times.
1570049 if (rpl->flags & MYSQL_RPL_SKIP_HEARTBEAT) {
7470 14110 Log_event_type event_type =
7471 14110 (Log_event_type)net->read_pos[1 + EVENT_TYPE_OFFSET];
7472
2/4
✓ Branch 0 taken 14110 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 14110 times.
14110 if ((event_type == binary_log::HEARTBEAT_LOG_EVENT) ||
7473 (event_type == binary_log::HEARTBEAT_LOG_EVENT_V2))
7474 continue;
7475 }
7476
7477 1570049 rpl->buffer = net->read_pos;
7478 1570049 rpl->size = packet_len;
7479 1570049 return 0;
7480 }
7481 1577199 }
7482
7483 /**
7484 Close replication stream.
7485
7486 @param mysql Connection handle.
7487 @param rpl Replication stream information.
7488 */
7489 27 void STDCALL mysql_binlog_close(MYSQL *mysql, MYSQL_RPL *rpl) {
7490
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 DBUG_TRACE;
7491
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
27 assert(mysql);
7492
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
27 assert(rpl);
7493
7494
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 end_server(mysql);
7495
7496 27 rpl->buffer = nullptr;
7497 27 rpl->size = 0;
7498 27 }
7499
7500 /**************************************************************************
7501 Set current database
7502 **************************************************************************/
7503
7504 2252 int STDCALL mysql_select_db(MYSQL *mysql, const char *db) {
7505 int error;
7506
1/2
✓ Branch 0 taken 2252 times.
✗ Branch 1 not taken.
2252 DBUG_TRACE;
7507
3/8
✓ Branch 0 taken 2252 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2252 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2252 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2252 DBUG_PRINT("enter", ("db: '%s'", db));
7508
7509
4/8
✓ Branch 0 taken 2252 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2252 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 28 times.
✓ Branch 7 taken 2224 times.
2252 if ((error = simple_command(mysql, COM_INIT_DB, (const uchar *)db,
7510 (ulong)strlen(db), 0)))
7511 28 return error;
7512
1/2
✓ Branch 0 taken 2224 times.
✗ Branch 1 not taken.
2224 my_free(mysql->db);
7513
1/2
✓ Branch 0 taken 2224 times.
✗ Branch 1 not taken.
2224 mysql->db = my_strdup(key_memory_MYSQL, db, MYF(MY_WME));
7514 2224 return 0;
7515 2252 }
7516
7517 /*************************************************************************
7518 Send a QUIT to the server and close the connection
7519 If handle is allocated by mysql connect free it.
7520 *************************************************************************/
7521
7522 2078226 void mysql_close_free_options(MYSQL *mysql) {
7523
1/2
✓ Branch 0 taken 2078367 times.
✗ Branch 1 not taken.
2078226 DBUG_TRACE;
7524
7525
1/2
✓ Branch 0 taken 2078368 times.
✗ Branch 1 not taken.
2078367 my_free(mysql->options.user);
7526
1/2
✓ Branch 0 taken 2078358 times.
✗ Branch 1 not taken.
2078368 my_free(mysql->options.host);
7527
1/2
✓ Branch 0 taken 2078343 times.
✗ Branch 1 not taken.
2078358 my_free(mysql->options.password);
7528
1/2
✓ Branch 0 taken 2078345 times.
✗ Branch 1 not taken.
2078343 my_free(mysql->options.unix_socket);
7529
1/2
✓ Branch 0 taken 2078351 times.
✗ Branch 1 not taken.
2078345 my_free(mysql->options.db);
7530
1/2
✓ Branch 0 taken 2078349 times.
✗ Branch 1 not taken.
2078351 my_free(mysql->options.my_cnf_file);
7531
1/2
✓ Branch 0 taken 2078338 times.
✗ Branch 1 not taken.
2078349 my_free(mysql->options.my_cnf_group);
7532
1/2
✓ Branch 0 taken 2078341 times.
✗ Branch 1 not taken.
2078338 my_free(mysql->options.charset_dir);
7533
1/2
✓ Branch 0 taken 2078344 times.
✗ Branch 1 not taken.
2078341 my_free(mysql->options.charset_name);
7534
1/2
✓ Branch 0 taken 2078347 times.
✗ Branch 1 not taken.
2078344 my_free(mysql->options.bind_address);
7535
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2078341 times.
2078347 if (mysql->options.init_commands) {
7536
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 char **ptr = mysql->options.init_commands->begin();
7537
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 char **end = mysql->options.init_commands->end();
7538
3/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 6 times.
12 for (; ptr < end; ptr++) my_free(*ptr);
7539 6 mysql->options.init_commands->~Init_commands_array();
7540
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 my_free(mysql->options.init_commands);
7541 }
7542
1/2
✓ Branch 0 taken 2078348 times.
✗ Branch 1 not taken.
2078347 mysql_ssl_free(mysql);
7543 #if defined(_WIN32)
7544 my_free(mysql->options.shared_memory_base_name);
7545 #endif /* _WIN32 */
7546
2/2
✓ Branch 0 taken 2031574 times.
✓ Branch 1 taken 46774 times.
2078348 if (mysql->options.extension) {
7547
1/2
✓ Branch 0 taken 2031580 times.
✗ Branch 1 not taken.
2031574 my_free(mysql->options.extension->plugin_dir);
7548
1/2
✓ Branch 0 taken 2031579 times.
✗ Branch 1 not taken.
2031580 my_free(mysql->options.extension->default_auth);
7549
1/2
✓ Branch 0 taken 2031574 times.
✗ Branch 1 not taken.
2031579 my_free(mysql->options.extension->server_public_key_path);
7550
2/2
✓ Branch 0 taken 374159 times.
✓ Branch 1 taken 1657415 times.
2031574 delete mysql->options.extension->connection_attributes;
7551
1/2
✓ Branch 0 taken 2031552 times.
✗ Branch 1 not taken.
2031509 my_free(mysql->options.extension->compression_algorithm);
7552
1/2
✓ Branch 0 taken 2031577 times.
✗ Branch 1 not taken.
2031552 my_free(mysql->options.extension->ssl_session_data);
7553
1/2
✓ Branch 0 taken 2031584 times.
✗ Branch 1 not taken.
2031577 my_free(mysql->options.extension);
7554 }
7555 2078358 memset(&mysql->options, 0, sizeof(mysql->options));
7556 2078358 }
7557
7558 /*
7559 Free all memory allocated in a MYSQL handle but preserve
7560 current options if any.
7561 */
7562
7563 2191726 void mysql_close_free(MYSQL *mysql) {
7564 2191726 my_free(mysql->host_info);
7565 2191804 my_free(mysql->user);
7566 2191813 my_free(mysql->passwd);
7567 2191808 my_free(mysql->db);
7568
7569 /* Free extension if any */
7570
2/2
✓ Branch 0 taken 2051011 times.
✓ Branch 1 taken 140799 times.
2191810 if (mysql->extension)
7571 2051011 mysql_extension_free(static_cast<MYSQL_EXTENSION *>(mysql->extension));
7572
7573 2191807 my_free(mysql->field_alloc);
7574
7575
2/2
✓ Branch 0 taken 19912 times.
✓ Branch 1 taken 2171898 times.
2191810 if (mysql->connector_fd)
7576 19912 free_vio_ssl_acceptor_fd(
7577 19912 reinterpret_cast<st_VioSSLFd *>(mysql->connector_fd));
7578 2191811 mysql->connector_fd = nullptr;
7579
7580 2191811 mysql->field_alloc = nullptr;
7581
7582 /* Clear pointers for better safety */
7583 2191811 mysql->host_info = nullptr;
7584 2191811 mysql->user = nullptr;
7585 2191811 mysql->passwd = nullptr;
7586 2191811 mysql->db = nullptr;
7587 2191811 mysql->extension = nullptr;
7588 2191811 }
7589
7590 /**
7591 For use when the connection to the server has been lost (in which case
7592 the server has discarded all information about prepared statements
7593 associated with the connection).
7594
7595 Mark all statements in mysql->stmts by setting stmt->mysql= 0 if the
7596 statement has transitioned beyond the MYSQL_STMT_INIT_DONE state, and
7597 unlink the statement from the mysql->stmts list.
7598
7599 The remaining pruned list of statements (if any) is kept in mysql->stmts.
7600
7601 @param mysql pointer to the MYSQL object
7602 */
7603 635788 static void mysql_prune_stmt_list(MYSQL *mysql) {
7604 635788 LIST *pruned_list = nullptr;
7605
7606
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 635781 times.
635786 while (mysql->stmts) {
7607 5 LIST *element = mysql->stmts;
7608 MYSQL_STMT *stmt;
7609
7610 5 mysql->stmts = list_delete(element, element);
7611 5 stmt = (MYSQL_STMT *)element->data;
7612
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
5 if (stmt->state != MYSQL_STMT_INIT_DONE) {
7613 3 stmt->mysql = nullptr;
7614 3 stmt->last_errno = CR_SERVER_LOST;
7615 3 my_stpcpy(stmt->last_error, ER_CLIENT(CR_SERVER_LOST));
7616 3 my_stpcpy(stmt->sqlstate, unknown_sqlstate);
7617 } else {
7618 2 pruned_list = list_add(pruned_list, element);
7619 }
7620 }
7621
7622 635781 mysql->stmts = pruned_list;
7623 635781 }
7624
7625 /*
7626 Clear connection pointer of every statement: this is necessary
7627 to give error on attempt to use a prepared statement of closed
7628 connection.
7629
7630 SYNOPSIS
7631 mysql_detach_stmt_list()
7632 stmt_list pointer to mysql->stmts
7633 func_name name of calling function
7634
7635 NOTE
7636 There is similar code in mysql_reconnect(), so changes here
7637 should also be reflected there.
7638 */
7639
7640 416638 void mysql_detach_stmt_list(LIST **stmt_list [[maybe_unused]],
7641 const char *func_name [[maybe_unused]]) {
7642 #ifndef MYSQL_SERVER
7643 /* Reset connection handle in all prepared statements. */
7644 405217 LIST *element = *stmt_list;
7645 char buff[MYSQL_ERRMSG_SIZE];
7646
1/2
✓ Branch 0 taken 405267 times.
✗ Branch 1 not taken.
405217 DBUG_TRACE;
7647
7648 405267 snprintf(buff, sizeof(buff) - 1, ER_CLIENT(CR_STMT_CLOSED), func_name);
7649
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 405224 times.
405227 for (; element; element = element->next) {
7650 3 MYSQL_STMT *stmt = (MYSQL_STMT *)element->data;
7651
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 set_stmt_error(stmt, CR_STMT_CLOSED, unknown_sqlstate, buff);
7652 3 stmt->mysql = nullptr;
7653 /* No need to call list_delete for statement here */
7654 }
7655 405224 *stmt_list = nullptr;
7656 810485 return;
7657 #endif /* !MYSQL_SERVER */
7658 416645 }
7659
7660 416316 void STDCALL mysql_close(MYSQL *mysql) {
7661
1/2
✓ Branch 0 taken 416461 times.
✗ Branch 1 not taken.
416316 DBUG_TRACE;
7662
2/2
✓ Branch 0 taken 416324 times.
✓ Branch 1 taken 137 times.
416461 if (mysql) /* Some simple safety */
7663 {
7664 /* If connection is still up, send a QUIT message */
7665
2/2
✓ Branch 0 taken 359024 times.
✓ Branch 1 taken 57300 times.
416324 if (mysql->net.vio != nullptr &&
7666
2/2
✓ Branch 0 taken 359023 times.
✓ Branch 1 taken 1 times.
359024 mysql->net.last_errno != NET_ERROR_SOCKET_UNUSABLE &&
7667
1/2
✓ Branch 0 taken 359025 times.
✗ Branch 1 not taken.
359023 mysql->net.last_errno != NET_ERROR_SOCKET_NOT_WRITABLE) {
7668
1/2
✓ Branch 0 taken 358992 times.
✗ Branch 1 not taken.
359025 free_old_query(mysql);
7669 358992 mysql->status = MYSQL_STATUS_READY; /* Force command */
7670 358992 bool old_reconnect = mysql->reconnect;
7671 358992 mysql->reconnect = false; // avoid recursion
7672
3/4
✓ Branch 0 taken 359024 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 358589 times.
✓ Branch 3 taken 435 times.
358992 if (vio_is_blocking(mysql->net.vio)) {
7673
3/6
✓ Branch 0 taken 358588 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 358579 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
358589 simple_command(mysql, COM_QUIT, (uchar *)nullptr, 0, 1);
7674 } else {
7675 /*
7676 Best effort; try to toss a command on the wire, but we can't wait
7677 to hear back.
7678 */
7679 bool err; /* unused */
7680
1/2
✓ Branch 0 taken 435 times.
✗ Branch 1 not taken.
435 simple_command_nonblocking(mysql, COM_QUIT, (uchar *)nullptr, 0, 1,
7681 &err);
7682 }
7683 359014 mysql->reconnect = old_reconnect;
7684
1/2
✓ Branch 0 taken 358988 times.
✗ Branch 1 not taken.
359014 end_server(mysql); /* Sets mysql->net.vio= 0 */
7685 }
7686
1/2
✓ Branch 0 taken 416330 times.
✗ Branch 1 not taken.
416287 mysql_close_free(mysql);
7687
1/2
✓ Branch 0 taken 416288 times.
✗ Branch 1 not taken.
416330 mysql_close_free_options(mysql);
7688
1/2
✓ Branch 0 taken 416312 times.
✗ Branch 1 not taken.
416288 mysql_detach_stmt_list(&mysql->stmts, "mysql_close");
7689
2/2
✓ Branch 0 taken 218164 times.
✓ Branch 1 taken 198148 times.
416312 if (mysql->free_me) {
7690
1/2
✓ Branch 0 taken 218182 times.
✗ Branch 1 not taken.
218164 my_free(mysql);
7691 }
7692 }
7693 416467 }
7694
7695 20085635 static bool cli_read_query_result(MYSQL *mysql) {
7696 uchar *pos;
7697 ulong field_count;
7698 ulong length;
7699
1/2
✓ Branch 0 taken 20085784 times.
✗ Branch 1 not taken.
20085635 DBUG_TRACE;
7700
7701
3/4
✓ Branch 0 taken 20085551 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 95799 times.
✓ Branch 3 taken 19989752 times.
20085784 if ((length = cli_safe_read(mysql, nullptr)) == packet_error) return true;
7702
1/2
✓ Branch 0 taken 19989981 times.
✗ Branch 1 not taken.
19989752 free_old_query(mysql); /* Free old result */
7703 #ifndef MYSQL_SERVER /* Avoid warn of unused labels*/
7704 19928360 get_info:
7705 #endif
7706 19991256 pos = (uchar *)mysql->net.read_pos;
7707
3/4
✓ Branch 0 taken 19991070 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9530809 times.
✓ Branch 3 taken 10460261 times.
19991256 if ((field_count = net_field_length(&pos)) == 0) {
7708
1/2
✓ Branch 0 taken 9530748 times.
✗ Branch 1 not taken.
9530809 read_ok_ex(mysql, length);
7709 #if defined(CLIENT_PROTOCOL_TRACING)
7710
2/2
✓ Branch 0 taken 80844 times.
✓ Branch 1 taken 9426412 times.
9507256 if (mysql->server_status & SERVER_MORE_RESULTS_EXISTS)
7711
2/10
✓ Branch 0 taken 80844 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 80844 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
80844 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_RESULT);
7712 else
7713
3/10
✓ Branch 0 taken 9426348 times.
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9426348 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
9426412 MYSQL_TRACE_STAGE(mysql, READY_FOR_COMMAND);
7714 #endif
7715 9530684 return false;
7716 }
7717 #ifndef MYSQL_SERVER
7718
2/2
✓ Branch 0 taken 1277 times.
✓ Branch 1 taken 10419580 times.
10420857 if (field_count == NULL_LENGTH) /* LOAD DATA LOCAL INFILE */
7719 {
7720 int error;
7721
7722
2/10
✓ Branch 0 taken 1277 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1277 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
1277 MYSQL_TRACE_STAGE(mysql, FILE_REQUEST);
7723
7724
1/2
✓ Branch 0 taken 1277 times.
✗ Branch 1 not taken.
1277 error = handle_local_infile(mysql, (char *)pos);
7725
7726
2/10
✓ Branch 0 taken 1277 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1277 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
1277 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_RESULT);
7727
7728
6/8
✓ Branch 0 taken 1277 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1275 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1275 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 1275 times.
1277 if ((length = cli_safe_read(mysql, nullptr)) == packet_error || error)
7729 2 return true;
7730 1275 goto get_info; /* Get info packet */
7731 }
7732 #endif
7733
2/2
✓ Branch 0 taken 106251 times.
✓ Branch 1 taken 10352733 times.
10458984 if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT))
7734 106251 mysql->server_status |= SERVER_STATUS_IN_TRANS;
7735
7736
2/4
✓ Branch 0 taken 10459013 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10459013 times.
10458984 if (read_com_query_metadata(mysql, pos, field_count)) return true;
7737
7738 10459013 mysql->status = MYSQL_STATUS_GET_RESULT;
7739 10459013 mysql->field_count = (uint)field_count;
7740
7741
2/10
✓ Branch 0 taken 10419629 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10419629 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
10419609 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_ROW);
7742
7743
3/8
✓ Branch 0 taken 10459055 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10459055 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10459055 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
10459033 DBUG_PRINT("exit", ("ok"));
7744 10459056 return false;
7745 20085541 }
7746 27467646 static net_async_status cli_read_query_result_nonblocking(MYSQL *mysql) {
7747
1/2
✓ Branch 0 taken 27467646 times.
✗ Branch 1 not taken.
27467646 DBUG_TRACE;
7748 27467646 NET *net = &mysql->net;
7749
1/2
✓ Branch 0 taken 27467646 times.
✗ Branch 1 not taken.
27467646 NET_ASYNC *net_async = NET_ASYNC_DATA(net);
7750
2/6
✓ Branch 0 taken 27467646 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27467646 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
27467646 MYSQL_ASYNC *async_context = ASYNC_DATA(mysql);
7751 27467646 uchar *pos = nullptr;
7752 ulong field_count;
7753 ulong length;
7754
7755
2/2
✓ Branch 0 taken 157 times.
✓ Branch 1 taken 27467489 times.
27467646 if (net_async->async_read_query_result_status ==
7756 NET_ASYNC_READ_QUERY_RESULT_IDLE) {
7757 157 net_async->async_read_query_result_status =
7758 NET_ASYNC_READ_QUERY_RESULT_FIELD_COUNT;
7759 }
7760
7761
1/2
✓ Branch 0 taken 27467646 times.
✗ Branch 1 not taken.
27467646 if (net_async->async_read_query_result_status ==
7762 NET_ASYNC_READ_QUERY_RESULT_FIELD_COUNT) {
7763 net_async_status status =
7764
1/2
✓ Branch 0 taken 27467646 times.
✗ Branch 1 not taken.
27467646 cli_safe_read_nonblocking(mysql, nullptr, &length);
7765
2/2
✓ Branch 0 taken 27467489 times.
✓ Branch 1 taken 157 times.
27467646 if (status == NET_ASYNC_NOT_READY) {
7766 27467489 return NET_ASYNC_NOT_READY;
7767 }
7768
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 157 times.
157 if (length == packet_error) {
7769 if (NET_ASYNC_DATA(net) != nullptr)
7770 net_async->async_read_query_result_status =
7771 NET_ASYNC_READ_QUERY_RESULT_IDLE;
7772 async_context->async_op_status = ASYNC_OP_UNSET;
7773 async_context->async_query_state = QUERY_IDLE;
7774 async_context->async_query_length = 0;
7775 return NET_ASYNC_ERROR;
7776 }
7777 157 mysql->packet_length = length;
7778
7779
1/2
✓ Branch 0 taken 157 times.
✗ Branch 1 not taken.
157 free_old_query(mysql); /* Free old result */
7780 #ifndef MYSQL_SERVER /* Avoid warn of unused labels*/
7781 157 get_info:
7782 #endif
7783 157 pos = (uchar *)mysql->net.read_pos;
7784
3/4
✓ Branch 0 taken 157 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 35 times.
✓ Branch 3 taken 122 times.
157 if ((field_count = net_field_length(&pos)) == 0) {
7785
1/2
✓ Branch 0 taken 35 times.
✗ Branch 1 not taken.
35 read_ok_ex(mysql, length);
7786 #if defined(CLIENT_PROTOCOL_TRACING)
7787
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 24 times.
35 if (mysql->server_status & SERVER_MORE_RESULTS_EXISTS)
7788
2/10
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 11 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
11 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_RESULT);
7789 else
7790
2/10
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 24 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
24 MYSQL_TRACE_STAGE(mysql, READY_FOR_COMMAND);
7791 #endif
7792 35 net_async->async_read_query_result_status =
7793 NET_ASYNC_READ_QUERY_RESULT_IDLE;
7794 35 async_context->async_op_status = ASYNC_OP_UNSET;
7795 35 async_context->async_query_state = QUERY_IDLE;
7796 35 async_context->async_query_length = 0;
7797 35 return NET_ASYNC_COMPLETE;
7798 }
7799 #ifndef MYSQL_SERVER
7800
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 122 times.
122 if (field_count == NULL_LENGTH) /* LOAD DATA LOCAL INFILE */
7801 {
7802 int error;
7803
7804 MYSQL_TRACE_STAGE(mysql, FILE_REQUEST);
7805
7806 if (!(mysql->options.client_flag & CLIENT_LOCAL_FILES)) {
7807 set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
7808 net_async->async_read_query_result_status =
7809 NET_ASYNC_READ_QUERY_RESULT_IDLE;
7810 async_context->async_op_status = ASYNC_OP_UNSET;
7811 async_context->async_query_state = QUERY_IDLE;
7812 async_context->async_query_length = 0;
7813 return NET_ASYNC_ERROR;
7814 }
7815
7816 error = handle_local_infile(mysql, (char *)pos);
7817
7818 MYSQL_TRACE_STAGE(mysql, WAIT_FOR_RESULT);
7819
7820 /* TODO: Make LOAD DATA LOCAL INFILE asynchronous. */
7821 if ((length = cli_safe_read(mysql, nullptr)) == packet_error || error) {
7822 /*
7823 When processing of LOAD DATA fails, server sends an error packet,
7824 which is handled here, for async connections.
7825 */
7826 if (NET_ASYNC_DATA(net) != nullptr)
7827 net_async->async_read_query_result_status =
7828 NET_ASYNC_READ_QUERY_RESULT_IDLE;
7829 async_context->async_op_status = ASYNC_OP_UNSET;
7830 async_context->async_query_state = QUERY_IDLE;
7831 async_context->async_query_length = 0;
7832 return NET_ASYNC_ERROR;
7833 }
7834 goto get_info; /* Get info packet */
7835 }
7836 #endif
7837
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 122 times.
122 if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT))
7838 mysql->server_status |= SERVER_STATUS_IN_TRANS;
7839
7840 122 mysql->field_count = (uint)field_count;
7841 122 net_async->async_read_query_result_status =
7842 NET_ASYNC_READ_QUERY_RESULT_FIELD_INFO;
7843 }
7844
7845
1/2
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
122 if (net_async->async_read_query_result_status ==
7846 NET_ASYNC_READ_QUERY_RESULT_FIELD_INFO) {
7847 int res;
7848 244 net_async_status status = read_com_query_metadata_nonblocking(
7849
1/2
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
122 mysql, pos, mysql->field_count, &res);
7850
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 122 times.
122 if (status == NET_ASYNC_NOT_READY) {
7851 return NET_ASYNC_NOT_READY;
7852 }
7853
7854
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 122 times.
122 if (res) {
7855 net_async->async_read_query_result_status =
7856 NET_ASYNC_READ_QUERY_RESULT_IDLE;
7857 async_context->async_op_status = ASYNC_OP_UNSET;
7858 async_context->async_query_state = QUERY_IDLE;
7859 async_context->async_query_length = 0;
7860 return NET_ASYNC_ERROR;
7861 }
7862 }
7863
7864 122 mysql->status = MYSQL_STATUS_GET_RESULT;
7865
3/8
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 122 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 122 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
122 DBUG_PRINT("exit", ("ok, %u", mysql->field_count));
7866 122 net_async->async_read_query_result_status = NET_ASYNC_READ_QUERY_RESULT_IDLE;
7867 122 async_context->async_op_status = ASYNC_OP_UNSET;
7868 122 async_context->async_query_state = QUERY_IDLE;
7869 122 async_context->async_query_length = 0;
7870 122 return NET_ASYNC_COMPLETE;
7871 27467646 }
7872
7873 /**
7874 Helper function to serialize the parameters data.
7875
7876 @param mysql the mysql handle
7877 @param[out] pret_data out pointer to the data. set to nullptr if there's no
7878 data
7879 @param[out] pret_data_length length of the data in pred_data. 0 if there's no
7880 data
7881 @return operation status
7882 @retval non-zero failed
7883 @retval zero success. Check pret_*
7884 */
7885 21018321 static int mysql_prepare_com_query_parameters(MYSQL *mysql,
7886 unsigned char **pret_data,
7887 unsigned long *pret_data_length) {
7888
1/2
✓ Branch 0 taken 21018569 times.
✗ Branch 1 not taken.
21018321 DBUG_TRACE;
7889
1/4
✓ Branch 0 taken 21018573 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
21018569 MYSQL_EXTENSION *ext = MYSQL_EXTENSION_PTR(mysql);
7890
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21018573 times.
21018573 assert(ext);
7891 21018573 bool send_named_params =
7892 21018573 (mysql->server_capabilities & CLIENT_QUERY_ATTRIBUTES) != 0;
7893 21018573 *pret_data = nullptr;
7894 21018573 *pret_data_length = 0;
7895
2/2
✓ Branch 0 taken 20901474 times.
✓ Branch 1 taken 117099 times.
21018573 if (send_named_params) {
7896 /*
7897 The state is checked later in cli_advanced_command too, but it's
7898 already too late since the below will reset the NET buffers.
7899 So we need to check before doing the below too.
7900 */
7901
2/2
✓ Branch 0 taken 20901463 times.
✓ Branch 1 taken 11 times.
20901474 if (mysql->status != MYSQL_STATUS_READY ||
7902
2/2
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 20901376 times.
20901463 mysql->server_status & SERVER_MORE_RESULTS_EXISTS) {
7903
3/8
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
98 DBUG_PRINT("error", ("state: %d", mysql->status));
7904
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
7905 4 return 1;
7906 }
7907
7908
2/2
✓ Branch 0 taken 1789449 times.
✓ Branch 1 taken 19111927 times.
20901376 if (mysql->net.vio == nullptr) { /* Do reconnect if possible */
7909
2/2
✓ Branch 0 taken 139246 times.
✓ Branch 1 taken 1650203 times.
1789449 if (!mysql->reconnect) {
7910 /* If we don't have any vio there must be an error */
7911
2/2
✓ Branch 0 taken 420 times.
✓ Branch 1 taken 138826 times.
139246 if (mysql->net.last_errno == 0)
7912
1/2
✓ Branch 0 taken 420 times.
✗ Branch 1 not taken.
420 set_mysql_error(mysql, CR_SERVER_LOST, unknown_sqlstate);
7913 139246 return 1;
7914 }
7915
3/4
✓ Branch 0 taken 1650203 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1642763 times.
✓ Branch 3 taken 7440 times.
1650203 if (mysql_reconnect(mysql)) return 1;
7916 /* mysql has a new ext at this point, take it again */
7917
1/4
✓ Branch 0 taken 7440 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
7440 ext = MYSQL_EXTENSION_PTR(mysql);
7918
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7440 times.
7440 assert(ext);
7919 }
7920
7921
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19119340 times.
19119340 if (mysql_int_serialize_param_data(
7922 &mysql->net, ext->bind_info.n_params, ext->bind_info.bind,
7923
1/2
✓ Branch 0 taken 19119340 times.
✗ Branch 1 not taken.
19119367 const_cast<const char **>(ext->bind_info.names), 1, pret_data,
7924 pret_data_length, 1, true, true, true)) {
7925 set_mysql_error(mysql, mysql->net.last_errno, mysql->net.sqlstate);
7926 return 1;
7927 }
7928
2/6
✓ Branch 0 taken 19119369 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 19119369 times.
19119340 assert(ext == MYSQL_EXTENSION_PTR(mysql));
7929
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19119369 times.
19119369 assert(ext);
7930
1/2
✓ Branch 0 taken 19119438 times.
✗ Branch 1 not taken.
19119369 mysql_extension_bind_free(ext);
7931 }
7932 19236537 return 0;
7933 21018550 }
7934 /*
7935 Send the query and return so we can do something else.
7936 Needs to be followed by mysql_read_query_result() when we want to
7937 finish processing it.
7938 */
7939
7940 21018056 int STDCALL mysql_send_query(MYSQL *mysql, const char *query, ulong length) {
7941
1/2
✓ Branch 0 taken 21018416 times.
✗ Branch 1 not taken.
21018056 DBUG_TRACE;
7942
7943 21018416 bool extension_was_present = (mysql->extension != nullptr);
7944
7945 STATE_INFO *info;
7946
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21018416 times.
21018416 assert(mysql);
7947
7948
3/4
✓ Branch 0 taken 21017959 times.
✓ Branch 1 taken 457 times.
✓ Branch 2 taken 455 times.
✗ Branch 3 not taken.
21018416 MYSQL_EXTENSION *ext = MYSQL_EXTENSION_PTR(mysql);
7949
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21018414 times.
21018414 assert(ext);
7950
7951
7/10
✓ Branch 0 taken 21018403 times.
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 21018390 times.
✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 21018357 times.
✓ Branch 7 taken 44 times.
✓ Branch 8 taken 21018365 times.
✗ Branch 9 not taken.
21018414 if ((info = STATE_DATA(mysql))) free_state_change_info(ext);
7952 uchar *ret_data;
7953 unsigned long ret_data_length;
7954 int retval =
7955
1/2
✓ Branch 0 taken 21018406 times.
✗ Branch 1 not taken.
21018409 mysql_prepare_com_query_parameters(mysql, &ret_data, &ret_data_length);
7956 /*
7957 mysql->extension is allocated memory inside mysql_init() before
7958 establishing a client-server connection. When MYSQL_EXTENSION_PTR() is
7959 called here in mysql_send_query() or in
7960 mysql_prepare_com_query_parameters() it allocates memory to
7961 mysql->extension if it is null (disconnected client). This memory is not
7962 freed later. When another query is executed mysql->extension is reallocated
7963 memory and this will cause a memory leak. To avoid this, mysql->extension
7964 is freed here if it was null when mysql_send_query was called and client is
7965 disconnected.
7966 */
7967
3/4
✓ Branch 0 taken 455 times.
✓ Branch 1 taken 21017951 times.
✓ Branch 2 taken 455 times.
✗ Branch 3 not taken.
21018406 if (!extension_was_present && !mysql->net.vio) {
7968
1/2
✓ Branch 0 taken 455 times.
✗ Branch 1 not taken.
455 mysql_extension_free(static_cast<MYSQL_EXTENSION *>(mysql->extension));
7969 455 mysql->extension = nullptr;
7970 }
7971
2/2
✓ Branch 0 taken 1782013 times.
✓ Branch 1 taken 19236393 times.
21018406 if (retval) return 1;
7972
1/2
✓ Branch 0 taken 19236363 times.
✗ Branch 1 not taken.
19236393 int ret = (*mysql->methods->advanced_command)(
7973 mysql, COM_QUERY, ret_data, ret_data_length,
7974 19236363 pointer_cast<const uchar *>(query), length, true, nullptr);
7975
3/4
✓ Branch 0 taken 19119270 times.
✓ Branch 1 taken 117093 times.
✓ Branch 2 taken 19119228 times.
✗ Branch 3 not taken.
19236363 if (ret_data) my_free(ret_data);
7976 19236321 return ret;
7977 21018334 }
7978
7979 /**
7980 Executes the SQL statement pointed by query. This API is called by
7981 mysql_real_query_nonblocking to send query to server in asynchronous way.
7982
7983 @param[in] mysql connection handle
7984 @param[in] query query string to be executed
7985 @param[in] length length of query
7986
7987 @retval NET_ASYNC_ERROR query execution failed
7988 @retval NET_ASYNC_NOT_READY query not yet completed, call this API
7989 again
7990 @retval NET_ASYNC_COMPLETE query execution finished
7991 */
7992 13494 static net_async_status mysql_send_query_nonblocking_inner(MYSQL *mysql,
7993 const char *query,
7994 ulong length) {
7995
1/2
✓ Branch 0 taken 13494 times.
✗ Branch 1 not taken.
13494 DBUG_TRACE;
7996 STATE_INFO *info;
7997
7998
3/8
✓ Branch 0 taken 13494 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13494 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 13494 times.
✗ Branch 7 not taken.
13494 if ((info = STATE_DATA(mysql)))
7999
1/2
✓ Branch 0 taken 13494 times.
✗ Branch 1 not taken.
13494 free_state_change_info(static_cast<MYSQL_EXTENSION *>(mysql->extension));
8000
8001 bool ret;
8002
2/6
✓ Branch 0 taken 13494 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13494 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
13494 MYSQL_ASYNC *async_context = ASYNC_DATA(mysql);
8003
8004 13494 if ((*mysql->methods->advanced_command_nonblocking)(
8005
1/2
✓ Branch 0 taken 13494 times.
✗ Branch 1 not taken.
13494 mysql, COM_QUERY, async_context->async_qp_data,
8006 async_context->async_qp_data_length,
8007 pointer_cast<const uchar *>(query), length, true, nullptr,
8008
2/2
✓ Branch 0 taken 13345 times.
✓ Branch 1 taken 149 times.
13494 &ret) == NET_ASYNC_NOT_READY) {
8009 13345 return NET_ASYNC_NOT_READY;
8010 }
8011
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 149 times.
149 if (ret)
8012 return NET_ASYNC_ERROR;
8013 else
8014 149 return NET_ASYNC_COMPLETE;
8015 13494 }
8016
8017 /**
8018 Wrapper around mysql_send_query_nonblocking_inner to be called externally
8019
8020 @param[in] mysql connection handle
8021 @param[in] query query string to be executed
8022 @param[in] length length of query
8023
8024 @retval NET_ASYNC_ERROR query execution failed
8025 @retval NET_ASYNC_NOT_READY query not yet completed, call this API again
8026 @retval NET_ASYNC_COMPLETE query execution finished
8027 */
8028 211 net_async_status STDCALL mysql_send_query_nonblocking(MYSQL *mysql,
8029 const char *query,
8030 ulong length) {
8031
1/2
✓ Branch 0 taken 211 times.
✗ Branch 1 not taken.
211 DBUG_TRACE;
8032
2/6
✓ Branch 0 taken 211 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 211 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
211 MYSQL_ASYNC *async_context = ASYNC_DATA(mysql);
8033 211 net_async_status ret = NET_ASYNC_NOT_READY;
8034
3/8
✓ Branch 0 taken 211 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 211 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 211 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
211 DBUG_PRINT("async", ("enter mysql_send_query_nonblocking state=%d",
8035 async_context->async_query_state));
8036
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 99 times.
211 if (async_context->async_query_state == QUERY_IDLE) {
8037
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
112 assert(async_context->async_qp_data == nullptr);
8038
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
112 assert(async_context->async_qp_data_length == 0);
8039
8040 112 async_context->async_query_length = length;
8041 112 async_context->async_query_state = QUERY_SENDING;
8042 112 async_context->async_op_status = ASYNC_OP_QUERY;
8043
3/8
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 112 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 112 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
112 DBUG_PRINT("async", ("set state=%d", async_context->async_query_state));
8044
8045
2/4
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 112 times.
112 if (mysql_prepare_com_query_parameters(
8046 mysql, &async_context->async_qp_data,
8047 &async_context->async_qp_data_length)) {
8048 set_query_idle(async_context);
8049 return NET_ASYNC_ERROR;
8050 }
8051 }
8052
8053
1/2
✓ Branch 0 taken 211 times.
✗ Branch 1 not taken.
211 ret = mysql_send_query_nonblocking_inner(mysql, query, length);
8054
8055
2/2
✓ Branch 0 taken 99 times.
✓ Branch 1 taken 112 times.
211 if (ret == NET_ASYNC_NOT_READY)
8056 99 return ret;
8057
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
112 else if (ret == NET_ASYNC_ERROR) {
8058 set_query_idle(async_context);
8059 return ret;
8060 }
8061
8062 112 async_context->async_query_state = QUERY_READING_RESULT;
8063
3/8
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 112 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 112 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
112 DBUG_PRINT("async", ("set state=%d", async_context->async_query_state));
8064 /*
8065 Technically we don't need to keep the query attributes data until the
8066 state change as they're stored into the NET at the first call to
8067 advanced_command. But since advanced_command() requires these we
8068 keep them as they are.
8069 */
8070
1/2
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
112 free_async_qp_data(async_context);
8071 112 return ret;
8072 211 }
8073
8074 10608437 int STDCALL mysql_real_query(MYSQL *mysql, const char *query, ulong length) {
8075 int retval;
8076
1/2
✓ Branch 0 taken 10608801 times.
✗ Branch 1 not taken.
10608437 DBUG_TRACE;
8077
3/8
✓ Branch 0 taken 10608738 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10608765 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10608765 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
10608801 DBUG_PRINT("enter", ("handle: %p", mysql));
8078
3/8
✓ Branch 0 taken 10608758 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10608736 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10608736 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
10608765 DBUG_PRINT("query", ("Query = '%-.*s'", (int)length, query));
8079
4/6
✓ Branch 0 taken 10608733 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 10608728 times.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
10608736 DBUG_EXECUTE_IF("inject_ER_NET_READ_INTERRUPTED", {
8080 mysql->net.last_errno = ER_NET_READ_INTERRUPTED;
8081 DBUG_SET("-d,inject_ER_NET_READ_INTERRUPTED");
8082 return 1;
8083 });
8084
8085
3/4
✓ Branch 0 taken 10608751 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 138808 times.
✓ Branch 3 taken 10469943 times.
10608728 if (mysql_send_query(mysql, query, length)) return 1;
8086
1/2
✓ Branch 0 taken 10469745 times.
✗ Branch 1 not taken.
10469943 retval = (int)(*mysql->methods->read_query_result)(mysql);
8087
2/6
✓ Branch 0 taken 10469900 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 10469955 times.
✗ Branch 5 not taken.
10469745 mysql_extension_bind_free(MYSQL_EXTENSION_PTR(mysql));
8088 10469955 return retval;
8089 10608768 }
8090
8091 /**
8092 Executes the SQL statement pointed by query. This sql statement length is set
8093 in length parameter. query string can contain multiple sql statements
8094 separated by semicolons. This function can return immediately with status set
8095 to NET_ASYNC_NOT_READY, in this case client application is expected to call
8096 this API until it returns NET_ASYNC_COMPLETE.
8097
8098 @param[in] mysql connection handle
8099 @param[in] query query string to be executed
8100 @param[in] length length of query
8101
8102 @retval NET_ASYNC_ERROR query execution failed
8103 @retval NET_ASYNC_NOT_READY query not yet completed, call this API again
8104 @retval NET_ASYNC_COMPLETE query execution finished
8105 */
8106 6203999 net_async_status STDCALL mysql_real_query_nonblocking(MYSQL *mysql,
8107 const char *query,
8108 ulong length) {
8109
1/2
✓ Branch 0 taken 6203999 times.
✗ Branch 1 not taken.
6203999 DBUG_TRACE;
8110
3/8
✓ Branch 0 taken 6203999 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6203999 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6203999 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
6203999 DBUG_PRINT("enter", ("handle: %p", mysql));
8111
3/8
✓ Branch 0 taken 6203999 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6203999 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6203999 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
6203999 DBUG_PRINT("query", ("Query = '%-.*s'", (int)length, query));
8112
2/6
✓ Branch 0 taken 6203999 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6203999 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
6203999 DBUG_EXECUTE_IF("inject_ER_NET_READ_INTERRUPTED", {
8113 mysql->net.last_errno = ER_NET_READ_INTERRUPTED;
8114 DBUG_SET("-d,inject_ER_NET_READ_INTERRUPTED");
8115 return NET_ASYNC_ERROR;
8116 });
8117
2/6
✓ Branch 0 taken 6203999 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6203999 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
6203999 MYSQL_ASYNC *async_context = ASYNC_DATA(mysql);
8118
3/4
✓ Branch 0 taken 6203962 times.
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6203962 times.
6203999 assert(async_context->async_op_status == ASYNC_OP_UNSET ||
8119 async_context->async_op_status == ASYNC_OP_QUERY);
8120
8121 6203999 net_async_status status = NET_ASYNC_NOT_READY;
8122
3/8
✓ Branch 0 taken 6203999 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6203999 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6203999 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
6203999 DBUG_PRINT("async", ("mysql_real_query_nonblocking start state=%d",
8123 async_context->async_query_state));
8124 /* 1st phase: send query. */
8125
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 6203962 times.
6203999 if (async_context->async_query_state == QUERY_IDLE) {
8126
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
37 assert(async_context->async_qp_data == nullptr);
8127
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
37 assert(async_context->async_qp_data_length == 0);
8128
2/4
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 37 times.
37 if (mysql_prepare_com_query_parameters(
8129 mysql, &async_context->async_qp_data,
8130 &async_context->async_qp_data_length)) {
8131 status = NET_ASYNC_ERROR;
8132 goto end;
8133 }
8134 37 async_context->async_query_length = length;
8135 37 async_context->async_op_status = ASYNC_OP_QUERY;
8136 37 async_context->async_query_state = QUERY_SENDING;
8137
3/8
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 37 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
37 DBUG_PRINT("async", ("set state=%d", async_context->async_query_state));
8138 }
8139
8140
2/2
✓ Branch 0 taken 13283 times.
✓ Branch 1 taken 6190716 times.
6203999 if (async_context->async_query_state == QUERY_SENDING) {
8141
1/2
✓ Branch 0 taken 13283 times.
✗ Branch 1 not taken.
13283 status = mysql_send_query_nonblocking_inner(mysql, query, length);
8142
2/2
✓ Branch 0 taken 13246 times.
✓ Branch 1 taken 37 times.
13283 if (status == NET_ASYNC_NOT_READY)
8143 13246 return NET_ASYNC_NOT_READY;
8144
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
37 else if (status == NET_ASYNC_ERROR)
8145 goto end;
8146 37 async_context->async_query_state = QUERY_READING_RESULT;
8147
3/8
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 37 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
37 DBUG_PRINT("async", ("set state=%d", async_context->async_query_state));
8148 /*
8149 Technically we don't need to keep the query attributes data until the
8150 state change as they're stored into the NET at the first call to
8151 advanced_command. But since advanced_command() requires these we
8152 keep them as they are.
8153 */
8154
1/2
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
37 if (async_context->async_qp_data) {
8155
1/2
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
37 my_free(async_context->async_qp_data);
8156 37 async_context->async_qp_data = nullptr;
8157 37 async_context->async_qp_data_length = 0;
8158 }
8159 }
8160
8161 /* 2nd phase: read query result (field count, field info) */
8162
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6190753 times.
6190753 if (async_context->async_query_state == QUERY_READING_RESULT) {
8163
1/2
✓ Branch 0 taken 6190753 times.
✗ Branch 1 not taken.
6190753 status = (*mysql->methods->read_query_result_nonblocking)(mysql);
8164
2/2
✓ Branch 0 taken 6190716 times.
✓ Branch 1 taken 37 times.
6190753 if (status == NET_ASYNC_NOT_READY)
8165 6190716 return NET_ASYNC_NOT_READY;
8166
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
37 else if (status == NET_ASYNC_ERROR)
8167 goto end;
8168 }
8169
8170 end:
8171 37 async_context->async_op_status = ASYNC_OP_UNSET;
8172 37 async_context->async_query_state = QUERY_IDLE;
8173
3/8
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 37 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
37 DBUG_PRINT("async", ("set state=%d", async_context->async_query_state));
8174 37 async_context->async_query_length = 0;
8175
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
37 if (status == NET_ASYNC_ERROR)
8176 return NET_ASYNC_ERROR;
8177 else
8178 37 return NET_ASYNC_COMPLETE;
8179 6203999 }
8180
8181 /**************************************************************************
8182 Alloc result struct for buffered results. All rows are read to buffer.
8183 mysql_data_seek may be used.
8184 **************************************************************************/
8185
8186 10618478 MYSQL_RES *STDCALL mysql_store_result(MYSQL *mysql) {
8187 MYSQL_RES *result;
8188
1/2
✓ Branch 0 taken 10618602 times.
✗ Branch 1 not taken.
10618478 DBUG_TRACE;
8189
8190 /*
8191 Some queries (e.g. "CALL") may return an empty resultset.
8192 mysql->field_count is 0 in such cases.
8193 */
8194
2/2
✓ Branch 0 taken 234116 times.
✓ Branch 1 taken 10384486 times.
10618602 if (!mysql->field_count) return nullptr;
8195
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 10384479 times.
10384486 if (mysql->status != MYSQL_STATUS_GET_RESULT) {
8196
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
8197 7 return nullptr;
8198 }
8199 10384479 mysql->status = MYSQL_STATUS_READY; /* server is ready */
8200
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10384468 times.
10384468 if (!(result = (MYSQL_RES *)my_malloc(
8201 key_memory_MYSQL_RES,
8202
1/2
✓ Branch 0 taken 10384468 times.
✗ Branch 1 not taken.
10384479 (uint)(sizeof(MYSQL_RES) + sizeof(ulong) * mysql->field_count),
8203 MYF(MY_WME | MY_ZEROFILL)))) {
8204 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
8205 return nullptr;
8206 }
8207
2/4
✓ Branch 0 taken 10384453 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10384453 times.
10384468 if (!(result->field_alloc = (MEM_ROOT *)my_malloc(
8208 key_memory_MYSQL, sizeof(MEM_ROOT), MYF(MY_WME | MY_ZEROFILL)))) {
8209 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
8210 my_free(result);
8211 return nullptr;
8212 }
8213 10384453 result->methods = mysql->methods;
8214 10384453 result->eof = true; /* Marker for buffered */
8215 10384453 result->lengths = (ulong *)(result + 1);
8216
3/4
✓ Branch 0 taken 10384446 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4641 times.
✓ Branch 3 taken 10379805 times.
10384453 if (!(result->data = (*mysql->methods->read_rows)(mysql, mysql->fields,
8217 mysql->field_count))) {
8218
1/2
✓ Branch 0 taken 4641 times.
✗ Branch 1 not taken.
4641 my_free(result->field_alloc);
8219
1/2
✓ Branch 0 taken 4641 times.
✗ Branch 1 not taken.
4641 my_free(result);
8220 4641 return nullptr;
8221 }
8222 10379805 mysql->affected_rows = result->row_count = result->data->rows;
8223 10379805 result->data_cursor = result->data->data;
8224 10379805 result->fields = mysql->fields;
8225 10379805 *result->field_alloc = std::move(*mysql->field_alloc);
8226 10379811 result->field_count = mysql->field_count;
8227 10379811 result->metadata = mysql->resultset_metadata;
8228 /* The rest of result members is zerofilled in my_malloc */
8229 10379811 mysql->fields = nullptr; /* fields is now in result */
8230 /* just in case this was mistakenly called after mysql_stmt_execute() */
8231 10379811 mysql->unbuffered_fetch_owner = nullptr;
8232 10379811 return result; /* Data fetched */
8233 10618575 }
8234
8235 /**
8236 This API reads all result set sent by server in an asynchronous way
8237
8238 @param[in] mysql connection handle
8239 @param[in] result buffer which holds all result sets.
8240
8241 @retval NET_ASYNC_NOT_READY reading of result sets not complete
8242 @retval NET_ASYNC_COMPLETE completed this asynchronous operation
8243 */
8244 enum net_async_status STDCALL
8245 263024 mysql_store_result_nonblocking(MYSQL *mysql, MYSQL_RES **result) {
8246
1/2
✓ Branch 0 taken 263024 times.
✗ Branch 1 not taken.
263024 DBUG_TRACE;
8247
2/6
✓ Branch 0 taken 263024 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 263024 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
263024 MYSQL_ASYNC *async_context = ASYNC_DATA(mysql);
8248 263024 *result = nullptr;
8249
8250 /*
8251 Some queries (e.g. "CALL") may return an empty resultset.
8252 mysql->field_count is 0 in such cases.
8253 */
8254
2/2
✓ Branch 0 taken 91992 times.
✓ Branch 1 taken 171032 times.
263024 if (!mysql->field_count) {
8255 91992 goto end;
8256 }
8257
2/2
✓ Branch 0 taken 131 times.
✓ Branch 1 taken 170901 times.
171032 if (!async_context->async_store_result_result) {
8258
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 131 times.
131 if (mysql->status != MYSQL_STATUS_GET_RESULT) {
8259 set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
8260 goto end;
8261 }
8262 131 mysql->status = MYSQL_STATUS_READY; /* server is ready */
8263
8264
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 131 times.
131 if (!(async_context->async_store_result_result = (MYSQL_RES *)my_malloc(
8265 key_memory_MYSQL_RES,
8266
1/2
✓ Branch 0 taken 131 times.
✗ Branch 1 not taken.
131 (uint)(sizeof(MYSQL_RES) + sizeof(ulong) * mysql->field_count),
8267 MYF(MY_WME | MY_ZEROFILL)))) {
8268 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
8269 goto end;
8270 }
8271 262 if (!(async_context->async_store_result_result->field_alloc =
8272
2/4
✓ Branch 0 taken 131 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 131 times.
131 (MEM_ROOT *)my_malloc(key_memory_MYSQL, sizeof(MEM_ROOT),
8273 MYF(MY_WME | MY_ZEROFILL)))) {
8274 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
8275 my_free(async_context->async_store_result_result);
8276 goto end;
8277 }
8278 131 async_context->async_store_result_result->methods = mysql->methods;
8279 131 async_context->async_store_result_result->eof =
8280 true; /* Marker for buffered */
8281 131 async_context->async_store_result_result->lengths =
8282 131 (ulong *)(async_context->async_store_result_result + 1);
8283 }
8284
8285 342064 if ((*mysql->methods->read_rows_nonblocking)(
8286 mysql, mysql->fields, mysql->field_count,
8287
3/4
✓ Branch 0 taken 171032 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 170901 times.
✓ Branch 3 taken 131 times.
171032 &async_context->async_store_result_result->data) ==
8288 NET_ASYNC_NOT_READY) {
8289 170901 return NET_ASYNC_NOT_READY;
8290 }
8291
8292
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 131 times.
131 if (!async_context->async_store_result_result->data) {
8293 my_free(async_context->async_store_result_result->field_alloc);
8294 my_free(async_context->async_store_result_result);
8295 goto end;
8296 }
8297 131 mysql->affected_rows = async_context->async_store_result_result->row_count =
8298 131 async_context->async_store_result_result->data->rows;
8299 131 async_context->async_store_result_result->data_cursor =
8300 131 async_context->async_store_result_result->data->data;
8301 131 async_context->async_store_result_result->fields = mysql->fields;
8302 131 *async_context->async_store_result_result->field_alloc =
8303 131 std::move(*mysql->field_alloc);
8304 131 async_context->async_store_result_result->field_count = mysql->field_count;
8305 131 async_context->async_store_result_result->metadata =
8306 131 mysql->resultset_metadata;
8307 /* The rest of result members is zerofilled in my_malloc */
8308 131 mysql->fields = nullptr; /* fields is now in result */
8309 /* just in case this was mistakenly called after mysql_stmt_execute() */
8310 131 mysql->unbuffered_fetch_owner = nullptr;
8311 131 *result = async_context->async_store_result_result;
8312 92123 end:
8313 92123 async_context->async_store_result_result = nullptr;
8314 92123 return NET_ASYNC_COMPLETE;
8315 263024 }
8316
8317 /**************************************************************************
8318 Alloc struct for use with unbuffered reads. Data is fetched by domand
8319 when calling to mysql_fetch_row.
8320 mysql_data_seek is a noop.
8321
8322 No other queries may be specified with the same MYSQL handle.
8323 There shouldn't be much processing per row because mysql server shouldn't
8324 have to wait for the client (and will not wait more than 30 sec/packet).
8325 **************************************************************************/
8326
8327 75365 static MYSQL_RES *cli_use_result(MYSQL *mysql) {
8328 MYSQL_RES *result;
8329
1/2
✓ Branch 0 taken 75365 times.
✗ Branch 1 not taken.
75365 DBUG_TRACE;
8330
8331 /*
8332 Some queries (e.g. "CALL") may return an empty resultset.
8333 mysql->field_count is 0 in such cases.
8334 */
8335
2/2
✓ Branch 0 taken 2781 times.
✓ Branch 1 taken 72584 times.
75365 if (!mysql->field_count) return nullptr;
8336
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 72583 times.
72584 if (mysql->status != MYSQL_STATUS_GET_RESULT) {
8337
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
8338 1 return nullptr;
8339 }
8340
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 72582 times.
72582 if (!(result = (MYSQL_RES *)my_malloc(
8341 key_memory_MYSQL_RES,
8342
1/2
✓ Branch 0 taken 72582 times.
✗ Branch 1 not taken.
72583 sizeof(*result) + sizeof(ulong) * mysql->field_count,
8343 MYF(MY_WME | MY_ZEROFILL))))
8344 return nullptr;
8345 72582 result->lengths = (ulong *)(result + 1);
8346 72582 result->methods = mysql->methods;
8347
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 72583 times.
72583 if (!(result->row = (MYSQL_ROW)my_malloc(
8348 key_memory_MYSQL_ROW,
8349
1/2
✓ Branch 0 taken 72583 times.
✗ Branch 1 not taken.
72582 sizeof(result->row[0]) * (mysql->field_count + 1),
8350 MYF(MY_WME)))) { /* Ptrs: to one row */
8351 my_free(result);
8352 return nullptr;
8353 }
8354
2/4
✓ Branch 0 taken 72583 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 72583 times.
72583 if (!(result->field_alloc = (MEM_ROOT *)my_malloc(
8355 key_memory_MYSQL, sizeof(MEM_ROOT), MYF(MY_WME | MY_ZEROFILL)))) {
8356 my_free(result->row);
8357 my_free(result);
8358 return nullptr;
8359 }
8360 72583 result->fields = mysql->fields;
8361 72583 *result->field_alloc = std::move(*mysql->field_alloc);
8362 72583 result->field_count = mysql->field_count;
8363 72583 result->metadata = mysql->resultset_metadata;
8364 72583 result->current_field = 0;
8365 72583 result->handle = mysql;
8366 72583 result->current_row = nullptr;
8367 72583 mysql->fields = nullptr; /* fields is now in result */
8368 72583 mysql->status = MYSQL_STATUS_USE_RESULT;
8369 72583 mysql->unbuffered_fetch_owner = &result->unbuffered_fetch_cancelled;
8370 72583 return result; /* Data is read to be fetched */
8371 75365 }
8372
8373 /**************************************************************************
8374 Return next row of the query results
8375 **************************************************************************/
8376
8377 78407053 MYSQL_ROW STDCALL mysql_fetch_row(MYSQL_RES *res) {
8378
1/2
✓ Branch 0 taken 78407262 times.
✗ Branch 1 not taken.
78407053 DBUG_TRACE;
8379
2/2
✓ Branch 0 taken 428811 times.
✓ Branch 1 taken 77978451 times.
78407262 if (!res->data) { /* Unbufferred fetch */
8380
2/2
✓ Branch 0 taken 428805 times.
✓ Branch 1 taken 6 times.
428811 if (!res->eof) {
8381 428805 MYSQL *mysql = res->handle;
8382
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 428805 times.
428805 if (mysql->status != MYSQL_STATUS_USE_RESULT) {
8383 set_mysql_error(mysql,
8384 res->unbuffered_fetch_cancelled
8385 ? CR_FETCH_CANCELED
8386 : CR_COMMANDS_OUT_OF_SYNC,
8387 unknown_sqlstate);
8388
3/4
✓ Branch 0 taken 428803 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 384811 times.
✓ Branch 3 taken 43992 times.
428805 } else if (!(read_one_row(mysql, res->field_count, res->row,
8389 res->lengths))) {
8390 384811 res->row_count++;
8391 384811 return res->current_row = res->row;
8392 }
8393
3/8
✓ Branch 0 taken 43992 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 43992 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 43992 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
43992 DBUG_PRINT("info", ("end of data"));
8394 43992 res->eof = true;
8395 43992 mysql->status = MYSQL_STATUS_READY;
8396 /*
8397 Reset only if owner points to us: there is a chance that somebody
8398 started new query after mysql_stmt_close():
8399 */
8400
1/2
✓ Branch 0 taken 43992 times.
✗ Branch 1 not taken.
43992 if (mysql->unbuffered_fetch_owner == &res->unbuffered_fetch_cancelled)
8401 43992 mysql->unbuffered_fetch_owner = nullptr;
8402 /* Don't clear handle in mysql_free_result */
8403 43992 res->handle = nullptr;
8404 }
8405 43998 return (MYSQL_ROW) nullptr;
8406 }
8407 {
8408 MYSQL_ROW tmp;
8409
2/2
✓ Branch 0 taken 1570761 times.
✓ Branch 1 taken 76407690 times.
77978451 if (!res->data_cursor) {
8410
3/8
✓ Branch 0 taken 1570788 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1570789 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1570789 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1570761 DBUG_PRINT("info", ("end of data"));
8411 1570791 return res->current_row = (MYSQL_ROW) nullptr;
8412 }
8413 76407690 tmp = res->data_cursor->data;
8414 76407690 res->data_cursor = res->data_cursor->next;
8415 76407690 return res->current_row = tmp;
8416 }
8417 78407290 }
8418 /**
8419 Reads next row of a result set in an asynchronous way.
8420
8421 @param[in] res buffer in which all rows are stored
8422 @param[out] row return pointer to one row from result set
8423
8424 @retval NET_ASYNC_NOT_READY fetch operation not complete, retry again
8425 @retval NET_ASYNC_COMPLETE fetch operation complete
8426 */
8427 222 net_async_status STDCALL mysql_fetch_row_nonblocking(MYSQL_RES *res,
8428 MYSQL_ROW *row) {
8429
1/2
✓ Branch 0 taken 222 times.
✗ Branch 1 not taken.
222 DBUG_TRACE;
8430 222 MYSQL *mysql = res->handle;
8431 222 *row = nullptr;
8432
8433
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 216 times.
222 if (!res->data) { /* Unbufferred fetch */
8434
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (!res->eof) {
8435 /*
8436 Can be -1 (error), 0 (success) and 1 (eof).
8437 Init to -1 so if state is not MYSQL_STATUS_USE_RESULT we get
8438 out of sync error.
8439 */
8440 6 int read_row_result = -1;
8441
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (mysql->status == MYSQL_STATUS_USE_RESULT) {
8442
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (read_one_row_nonblocking(mysql, res->field_count, res->row,
8443 res->lengths,
8444
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 &read_row_result) == NET_ASYNC_NOT_READY) {
8445 return NET_ASYNC_NOT_READY;
8446 }
8447
8448 // we arrive here on NET_ASYNC_ERROR or NET_ASYNC_COMPLETE
8449
8450
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
6 if (read_row_result == 0) { // we've got a row: process it
8451 5 res->row_count++;
8452 5 *row = res->current_row = res->row;
8453 5 goto end;
8454 }
8455 }
8456
8457
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (read_row_result == -1) // on row reading error
8458 set_mysql_error(mysql,
8459 res->unbuffered_fetch_cancelled
8460 ? CR_FETCH_CANCELED
8461 : CR_COMMANDS_OUT_OF_SYNC,
8462 unknown_sqlstate);
8463
3/8
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1 DBUG_PRINT("info", ("end of data"));
8464 1 res->eof = true;
8465 1 mysql->status = MYSQL_STATUS_READY;
8466 /*
8467 Reset only if owner points to us: there is a chance that
8468 somebody started new query after mysql_stmt_close():
8469 */
8470
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (mysql->unbuffered_fetch_owner == &res->unbuffered_fetch_cancelled)
8471 1 mysql->unbuffered_fetch_owner = nullptr;
8472 /* Don't clear handle in mysql_free_result */
8473 1 res->handle = nullptr;
8474 }
8475
8476 1 *row = nullptr;
8477 1 goto end;
8478 }
8479 {
8480 MYSQL_ROW tmp;
8481
2/2
✓ Branch 0 taken 93 times.
✓ Branch 1 taken 123 times.
216 if (!res->data_cursor) {
8482
3/8
✓ Branch 0 taken 93 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 93 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 93 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
93 DBUG_PRINT("info", ("end of data"));
8483 93 *row = nullptr;
8484 93 goto end;
8485 }
8486 123 tmp = res->data_cursor->data;
8487 123 res->data_cursor = res->data_cursor->next;
8488 123 *row = res->current_row = tmp;
8489 123 goto end;
8490 }
8491
8492 222 end:
8493 222 return NET_ASYNC_COMPLETE;
8494 222 }
8495
8496 /**************************************************************************
8497 Get column lengths of the current row
8498 If one uses mysql_use_result, res->lengths contains the length information,
8499 else the lengths are calculated from the offset between pointers.
8500 **************************************************************************/
8501
8502 75392796 ulong *STDCALL mysql_fetch_lengths(MYSQL_RES *res) {
8503 MYSQL_ROW column;
8504
8505
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 75392796 times.
75392796 if (!(column = res->current_row)) return nullptr; /* Something is wrong */
8506
2/2
✓ Branch 0 taken 75036979 times.
✓ Branch 1 taken 355817 times.
75392796 if (res->data)
8507 75036979 (*res->methods->fetch_lengths)(res->lengths, column, res->field_count);
8508 75392796 return res->lengths;
8509 }
8510
8511 /**
8512 Validates, makes into an absolute path and sets @ref
8513 MYSQL_OPT_LOAD_DATA_LOCAL_DIR value
8514
8515 @param mysql connection handle
8516 @param arg the value to set. Can be null
8517
8518 @retval true failed
8519 @retval false success
8520 */
8521 11 static bool set_load_data_local_infile_option(MYSQL *mysql, const char *arg) {
8522 char buff1[FN_REFLEN], buff2[FN_REFLEN];
8523
8524
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
11 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
8525
8526 // NULL is a valid argument
8527
2/4
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
11 if (arg == nullptr || !arg[0]) {
8528 EXTENSION_SET_STRING(&mysql->options, load_data_dir, nullptr);
8529 return false;
8530 }
8531
8532 // make fully qualified name
8533
2/4
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
11 if (my_realpath(buff1, arg, 0)) {
8534 char errbuf[MYSYS_STRERROR_SIZE];
8535 set_mysql_extended_error(
8536 mysql, CR_LOAD_DATA_LOCAL_INFILE_REALPATH_FAIL, unknown_sqlstate,
8537 ER_CLIENT(CR_LOAD_DATA_LOCAL_INFILE_REALPATH_FAIL), arg, my_errno(),
8538 my_strerror(errbuf, sizeof(errbuf), my_errno()));
8539 return true;
8540 }
8541
8542 // with uniform directory separators
8543
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 convert_dirname(buff2, buff1, NullS);
8544
3/8
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 11 times.
✗ Branch 7 not taken.
11 EXTENSION_SET_STRING(&mysql->options, load_data_dir, buff2);
8545 11 return false;
8546 }
8547
8548 14993478 int STDCALL mysql_options(MYSQL *mysql, enum mysql_option option,
8549 const void *arg) {
8550
1/2
✓ Branch 0 taken 14994171 times.
✗ Branch 1 not taken.
14993478 DBUG_TRACE;
8551
3/8
✓ Branch 0 taken 14993635 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14993039 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 14993039 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
14994171 DBUG_PRINT("enter", ("option: %d", (int)option));
8552
43/44
✓ Branch 0 taken 139542 times.
✓ Branch 1 taken 29046 times.
✓ Branch 2 taken 489 times.
✓ Branch 3 taken 66 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 103218 times.
✓ Branch 6 taken 6 times.
✓ Branch 7 taken 4 times.
✓ Branch 8 taken 4 times.
✓ Branch 9 taken 59070 times.
✓ Branch 10 taken 144227 times.
✓ Branch 11 taken 20634 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 3 times.
✓ Branch 14 taken 25792 times.
✓ Branch 15 taken 24 times.
✓ Branch 16 taken 55931 times.
✓ Branch 17 taken 665 times.
✓ Branch 18 taken 139078 times.
✓ Branch 19 taken 139078 times.
✓ Branch 20 taken 139081 times.
✓ Branch 21 taken 139068 times.
✓ Branch 22 taken 139069 times.
✓ Branch 23 taken 139022 times.
✓ Branch 24 taken 139073 times.
✓ Branch 25 taken 139069 times.
✓ Branch 26 taken 139083 times.
✓ Branch 27 taken 136123 times.
✓ Branch 28 taken 164811 times.
✓ Branch 29 taken 47200 times.
✓ Branch 30 taken 91588 times.
✓ Branch 31 taken 136124 times.
✓ Branch 32 taken 12298836 times.
✓ Branch 33 taken 16 times.
✓ Branch 34 taken 4 times.
✓ Branch 35 taken 134678 times.
✓ Branch 36 taken 28026 times.
✓ Branch 37 taken 27540 times.
✓ Branch 38 taken 2 times.
✓ Branch 39 taken 8350 times.
✓ Branch 40 taken 88793 times.
✓ Branch 41 taken 11 times.
✓ Branch 42 taken 42 times.
✗ Branch 43 not taken.
14992490 switch (option) {
8553 139542 case MYSQL_OPT_CONNECT_TIMEOUT:
8554 139542 mysql->options.connect_timeout = *static_cast<const uint *>(arg);
8555 139542 break;
8556 29046 case MYSQL_OPT_READ_TIMEOUT:
8557 29046 mysql->options.read_timeout = *static_cast<const uint *>(arg);
8558 29046 break;
8559 489 case MYSQL_OPT_WRITE_TIMEOUT:
8560 489 mysql->options.write_timeout = *static_cast<const uint *>(arg);
8561 489 break;
8562 66 case MYSQL_OPT_COMPRESS:
8563 66 mysql->options.compress = true; /* Remember for connect */
8564 66 mysql->options.client_flag |= CLIENT_COMPRESS;
8565 66 break;
8566 3 case MYSQL_OPT_NAMED_PIPE: /* This option is deprecated */
8567 3 mysql->options.protocol = MYSQL_PROTOCOL_PIPE; /* Force named pipe */
8568 3 break;
8569 103218 case MYSQL_OPT_LOCAL_INFILE: /* Allow LOAD DATA LOCAL ?*/
8570
3/4
✓ Branch 0 taken 102 times.
✓ Branch 1 taken 103116 times.
✓ Branch 2 taken 102 times.
✗ Branch 3 not taken.
103218 if (!arg || (*static_cast<const uint *>(arg) != 0))
8571 103218 mysql->options.client_flag |= CLIENT_LOCAL_FILES;
8572 else
8573 mysql->options.client_flag &= ~CLIENT_LOCAL_FILES;
8574 103218 break;
8575 6 case MYSQL_INIT_COMMAND:
8576
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 add_init_command(&mysql->options, static_cast<const char *>(arg));
8577 6 break;
8578 4 case MYSQL_READ_DEFAULT_FILE:
8579
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 my_free(mysql->options.my_cnf_file);
8580 4 mysql->options.my_cnf_file =
8581
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 my_strdup(key_memory_mysql_options, static_cast<const char *>(arg),
8582 MYF(MY_WME));
8583 4 break;
8584 4 case MYSQL_READ_DEFAULT_GROUP:
8585
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 my_free(mysql->options.my_cnf_group);
8586 4 mysql->options.my_cnf_group =
8587
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 my_strdup(key_memory_mysql_options, static_cast<const char *>(arg),
8588 MYF(MY_WME));
8589 4 break;
8590 59070 case MYSQL_SET_CHARSET_DIR:
8591
1/2
✓ Branch 0 taken 59070 times.
✗ Branch 1 not taken.
59070 my_free(mysql->options.charset_dir);
8592 59070 mysql->options.charset_dir =
8593
1/2
✓ Branch 0 taken 59070 times.
✗ Branch 1 not taken.
59070 my_strdup(key_memory_mysql_options, static_cast<const char *>(arg),
8594 MYF(MY_WME));
8595 59070 break;
8596 144227 case MYSQL_SET_CHARSET_NAME:
8597
1/2
✓ Branch 0 taken 144227 times.
✗ Branch 1 not taken.
144227 my_free(mysql->options.charset_name);
8598 144227 mysql->options.charset_name =
8599
1/2
✓ Branch 0 taken 144227 times.
✗ Branch 1 not taken.
144227 my_strdup(key_memory_mysql_options, static_cast<const char *>(arg),
8600 MYF(MY_WME));
8601 144227 break;
8602 20634 case MYSQL_OPT_PROTOCOL:
8603 20634 mysql->options.protocol = *static_cast<const uint *>(arg);
8604 20634 break;
8605 1 case MYSQL_SHARED_MEMORY_BASE_NAME:
8606 #if defined(_WIN32)
8607 my_free(mysql->options.shared_memory_base_name);
8608
8609 mysql->options.shared_memory_base_name =
8610 my_strdup(key_memory_mysql_options, static_cast<const char *>(arg),
8611 MYF(MY_WME));
8612 #endif
8613 1 break;
8614 3 case MYSQL_REPORT_DATA_TRUNCATION:
8615 3 mysql->options.report_data_truncation = *static_cast<const bool *>(arg);
8616 3 break;
8617 25792 case MYSQL_OPT_RECONNECT:
8618 25792 mysql->reconnect = *static_cast<const bool *>(arg);
8619 25792 break;
8620 24 case MYSQL_OPT_BIND:
8621
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 my_free(mysql->options.bind_address);
8622 24 mysql->options.bind_address =
8623
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 my_strdup(key_memory_mysql_options, static_cast<const char *>(arg),
8624 MYF(MY_WME));
8625 24 break;
8626 55931 case MYSQL_PLUGIN_DIR:
8627
5/10
✓ Branch 0 taken 55931 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 55931 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 55448 times.
✓ Branch 7 taken 483 times.
✓ Branch 8 taken 55448 times.
✗ Branch 9 not taken.
55931 EXTENSION_SET_STRING(&mysql->options, plugin_dir,
8628 static_cast<const char *>(arg));
8629 55931 break;
8630 665 case MYSQL_DEFAULT_AUTH:
8631
5/10
✓ Branch 0 taken 665 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 665 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 182 times.
✓ Branch 7 taken 483 times.
✓ Branch 8 taken 182 times.
✗ Branch 9 not taken.
665 EXTENSION_SET_STRING(&mysql->options, default_auth,
8632 static_cast<const char *>(arg));
8633 665 break;
8634 139078 case MYSQL_OPT_SSL_KEY:
8635
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 139078 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
139078 if (mysql->options.ssl_key) my_free(mysql->options.ssl_key);
8636 139078 mysql->options.ssl_key =
8637
1/2
✓ Branch 0 taken 139078 times.
✗ Branch 1 not taken.
139078 set_ssl_option_unpack_path(static_cast<const char *>(arg));
8638 139078 break;
8639 139078 case MYSQL_OPT_SSL_CERT:
8640
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 139078 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
139078 if (mysql->options.ssl_cert) my_free(mysql->options.ssl_cert);
8641 139078 mysql->options.ssl_cert =
8642
1/2
✓ Branch 0 taken 139078 times.
✗ Branch 1 not taken.
139078 set_ssl_option_unpack_path(static_cast<const char *>(arg));
8643 139078 break;
8644 139081 case MYSQL_OPT_SSL_CA:
8645
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 139081 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
139081 if (mysql->options.ssl_ca) my_free(mysql->options.ssl_ca);
8646 139081 mysql->options.ssl_ca =
8647
1/2
✓ Branch 0 taken 139081 times.
✗ Branch 1 not taken.
139081 set_ssl_option_unpack_path(static_cast<const char *>(arg));
8648 139081 break;
8649 139068 case MYSQL_OPT_SSL_CAPATH:
8650
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 139068 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
139068 if (mysql->options.ssl_capath) my_free(mysql->options.ssl_capath);
8651 139067 mysql->options.ssl_capath =
8652
1/2
✓ Branch 0 taken 139067 times.
✗ Branch 1 not taken.
139068 set_ssl_option_unpack_path(static_cast<const char *>(arg));
8653 139067 break;
8654 139069 case MYSQL_OPT_SSL_CIPHER:
8655
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 139069 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 104 times.
✓ Branch 5 taken 138965 times.
✓ Branch 6 taken 104 times.
✗ Branch 7 not taken.
139069 SET_OPTION(ssl_cipher, static_cast<const char *>(arg));
8656 139069 break;
8657 139022 case MYSQL_OPT_TLS_CIPHERSUITES:
8658
5/10
✓ Branch 0 taken 139022 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 139022 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✓ Branch 7 taken 139004 times.
✓ Branch 8 taken 18 times.
✗ Branch 9 not taken.
139022 EXTENSION_SET_STRING(&mysql->options, tls_ciphersuites,
8659 static_cast<const char *>(arg));
8660 139022 break;
8661 139073 case MYSQL_OPT_SSL_CRL:
8662
1/2
✓ Branch 0 taken 139073 times.
✗ Branch 1 not taken.
139073 if (mysql->options.extension)
8663
1/2
✓ Branch 0 taken 139073 times.
✗ Branch 1 not taken.
139073 my_free(mysql->options.extension->ssl_crl);
8664 else
8665 ALLOCATE_EXTENSIONS(&mysql->options);
8666 278146 mysql->options.extension->ssl_crl =
8667
1/2
✓ Branch 0 taken 139073 times.
✗ Branch 1 not taken.
139073 set_ssl_option_unpack_path(static_cast<const char *>(arg));
8668 139073 break;
8669 139069 case MYSQL_OPT_SSL_CRLPATH:
8670
1/2
✓ Branch 0 taken 139069 times.
✗ Branch 1 not taken.
139069 if (mysql->options.extension)
8671
1/2
✓ Branch 0 taken 139069 times.
✗ Branch 1 not taken.
139069 my_free(mysql->options.extension->ssl_crlpath);
8672 else
8673 ALLOCATE_EXTENSIONS(&mysql->options);
8674 278138 mysql->options.extension->ssl_crlpath =
8675
1/2
✓ Branch 0 taken 139069 times.
✗ Branch 1 not taken.
139069 set_ssl_option_unpack_path(static_cast<const char *>(arg));
8676 139069 break;
8677 139083 case MYSQL_OPT_TLS_VERSION:
8678
5/10
✓ Branch 0 taken 139083 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 139083 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 2999 times.
✓ Branch 7 taken 136084 times.
✓ Branch 8 taken 2998 times.
✗ Branch 9 not taken.
139083 EXTENSION_SET_STRING(&mysql->options, tls_version,
8679 static_cast<const char *>(arg));
8680 278165 if ((mysql->options.extension->ssl_ctx_flags = process_tls_version(
8681
3/4
✓ Branch 0 taken 139083 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 139069 times.
139082 mysql->options.extension->tls_version)) == -1)
8682 14 return 1;
8683 139069 break;
8684 136123 case MYSQL_OPT_SSL_FIPS_MODE: {
8685 136123 char ssl_err_string[OPENSSL_ERROR_LENGTH] = {'\0'};
8686
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 136123 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
136123 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
8687 136123 mysql->options.extension->ssl_fips_mode =
8688 136123 *static_cast<const ulong *>(arg);
8689
3/4
✓ Branch 0 taken 136123 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 136121 times.
136123 if (set_fips_mode(mysql->options.extension->ssl_fips_mode,
8690 ssl_err_string)) {
8691
3/8
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2 DBUG_PRINT("error", ("fips mode set error %s:", ssl_err_string));
8692
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 set_mysql_extended_error(
8693 mysql, CR_SSL_FIPS_MODE_ERR, unknown_sqlstate,
8694 "Set Fips mode ON/STRICT failed, detail: '%s'.", ssl_err_string);
8695 2 return 1;
8696 }
8697 136121 } break;
8698 164811 case MYSQL_OPT_SSL_MODE:
8699
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 164811 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
164811 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
8700 164811 mysql->options.extension->ssl_mode = *static_cast<const uint *>(arg);
8701
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 164774 times.
164811 if (mysql->options.extension->ssl_mode == SSL_MODE_VERIFY_IDENTITY)
8702 37 mysql->options.client_flag |= CLIENT_SSL_VERIFY_SERVER_CERT;
8703 else
8704 164774 mysql->options.client_flag &= ~CLIENT_SSL_VERIFY_SERVER_CERT;
8705 164811 break;
8706 47200 case MYSQL_SERVER_PUBLIC_KEY:
8707
4/10
✓ Branch 0 taken 47200 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 47200 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 47200 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 47200 times.
✗ Branch 9 not taken.
47200 EXTENSION_SET_STRING(&mysql->options, server_public_key_path,
8708 static_cast<const char *>(arg));
8709 47200 break;
8710
8711 91588 case MYSQL_OPT_GET_SERVER_PUBLIC_KEY:
8712
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 91588 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
91588 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
8713 91588 mysql->options.extension->get_server_public_key =
8714 91588 *static_cast<const bool *>(arg);
8715 91588 break;
8716
8717 136124 case MYSQL_OPT_CONNECT_ATTR_RESET:
8718
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 136124 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
136124 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
8719
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 136122 times.
136124 if (mysql->options.extension->connection_attributes) {
8720
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 delete mysql->options.extension->connection_attributes;
8721 2 mysql->options.extension->connection_attributes = nullptr;
8722 2 mysql->options.extension->connection_attributes_length = 0;
8723 }
8724 136124 break;
8725 12298836 case MYSQL_OPT_CONNECT_ATTR_DELETE:
8726
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 12298836 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
12298836 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
8727
2/2
✓ Branch 0 taken 10918525 times.
✓ Branch 1 taken 1380311 times.
12298836 if (mysql->options.extension->connection_attributes) {
8728
2/4
✓ Branch 0 taken 10918525 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10918525 times.
✗ Branch 3 not taken.
10918525 string key = arg ? pointer_cast<const char *>(arg) : "";
8729
8730
1/2
✓ Branch 0 taken 10918525 times.
✗ Branch 1 not taken.
10918525 if (!key.empty()) {
8731 auto it =
8732
1/2
✓ Branch 0 taken 10918525 times.
✗ Branch 1 not taken.
10918525 mysql->options.extension->connection_attributes->hash.find(key);
8733 10918525 if (it !=
8734
2/2
✓ Branch 0 taken 8378996 times.
✓ Branch 1 taken 2539529 times.
21837050 mysql->options.extension->connection_attributes->hash.end()) {
8735 8378996 const string &attr_key = it->first;
8736 8378996 const string &attr_value = it->second;
8737 8378996 mysql->options.extension->connection_attributes_length -=
8738
1/2
✓ Branch 0 taken 8378996 times.
✗ Branch 1 not taken.
8378996 get_length_store_length(attr_key.size()) + attr_key.size() +
8739
1/2
✓ Branch 0 taken 8378996 times.
✗ Branch 1 not taken.
8378996 get_length_store_length(attr_value.size()) + attr_value.size();
8740
8741
1/2
✓ Branch 0 taken 8378996 times.
✗ Branch 1 not taken.
8378996 mysql->options.extension->connection_attributes->hash.erase(it);
8742 }
8743 }
8744 10918525 }
8745 12298836 break;
8746 16 case MYSQL_ENABLE_CLEARTEXT_PLUGIN:
8747
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
16 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
8748 16 mysql->options.extension->enable_cleartext_plugin =
8749 16 *static_cast<const bool *>(arg);
8750 16 break;
8751 4 case MYSQL_OPT_RETRY_COUNT:
8752
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
4 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
8753 4 mysql->options.extension->retry_count = *static_cast<const uint *>(arg);
8754 4 break;
8755 134678 case MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS:
8756
2/2
✓ Branch 0 taken 102648 times.
✓ Branch 1 taken 32030 times.
134678 if (*static_cast<const bool *>(arg))
8757 102648 mysql->options.client_flag |= CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS;
8758 else
8759 32030 mysql->options.client_flag &= ~CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS;
8760 134678 break;
8761
8762 28026 case MYSQL_OPT_MAX_ALLOWED_PACKET:
8763
2/2
✓ Branch 0 taken 490 times.
✓ Branch 1 taken 27536 times.
28026 if (mysql)
8764 490 mysql->options.max_allowed_packet = *static_cast<const ulong *>(arg);
8765 else
8766 27536 g_max_allowed_packet = *static_cast<const ulong *>(arg);
8767 28026 break;
8768
8769 27540 case MYSQL_OPT_NET_BUFFER_LENGTH:
8770 27540 g_net_buffer_length = *static_cast<const ulong *>(arg);
8771 27540 break;
8772
8773 2 case MYSQL_OPT_OPTIONAL_RESULTSET_METADATA:
8774
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (*static_cast<const bool *>(arg))
8775 2 mysql->options.client_flag |= CLIENT_OPTIONAL_RESULTSET_METADATA;
8776 else
8777 mysql->options.client_flag &= ~CLIENT_OPTIONAL_RESULTSET_METADATA;
8778 2 break;
8779
8780 8350 case MYSQL_OPT_COMPRESSION_ALGORITHMS: {
8781
1/2
✓ Branch 0 taken 8350 times.
✗ Branch 1 not taken.
8350 std::string compress_option(static_cast<const char *>(arg));
8782 8350 std::vector<std::string> list;
8783
2/4
✓ Branch 0 taken 8350 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8350 times.
✗ Branch 3 not taken.
8350 parse_compression_algorithms_list(compress_option, list);
8784
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 8350 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
8350 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
8785 8350 mysql->options.extension->connection_compressed = true;
8786 8350 mysql->options.client_flag &=
8787 ~(CLIENT_COMPRESS | CLIENT_ZSTD_COMPRESSION_ALGORITHM);
8788 8350 mysql->options.compress = false;
8789 8350 auto it = list.begin();
8790 8350 unsigned int cnt = 0;
8791
5/6
✓ Branch 0 taken 8478 times.
✓ Branch 1 taken 8350 times.
✓ Branch 2 taken 8478 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8478 times.
✓ Branch 5 taken 8350 times.
16828 while (it != list.end() && cnt < COMPRESSION_ALGORITHM_COUNT_MAX) {
8792
1/2
✓ Branch 0 taken 8478 times.
✗ Branch 1 not taken.
8478 std::string value = *it;
8793
6/9
✓ Branch 0 taken 8478 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8478 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 146 times.
✓ Branch 5 taken 144 times.
✓ Branch 6 taken 8183 times.
✓ Branch 7 taken 5 times.
✗ Branch 8 not taken.
8478 switch (get_compression_algorithm(value)) {
8794 146 case enum_compression_algorithm::MYSQL_ZLIB:
8795 146 mysql->options.client_flag |= CLIENT_COMPRESS;
8796 146 mysql->options.compress = true;
8797 146 break;
8798 144 case enum_compression_algorithm::MYSQL_ZSTD:
8799 144 mysql->options.client_flag |= CLIENT_ZSTD_COMPRESSION_ALGORITHM;
8800 144 mysql->options.compress = true;
8801 144 break;
8802 8183 case enum_compression_algorithm::MYSQL_UNCOMPRESSED:
8803 8183 mysql->options.extension->connection_compressed = false;
8804 8183 break;
8805 5 case enum_compression_algorithm::MYSQL_INVALID:
8806 5 break; // report error
8807 }
8808 8478 it++;
8809 8478 cnt++;
8810 8478 }
8811
2/2
✓ Branch 0 taken 8349 times.
✓ Branch 1 taken 1 times.
8350 if (cnt)
8812
4/10
✓ Branch 0 taken 8349 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8349 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 8349 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 8349 times.
✗ Branch 9 not taken.
8349 EXTENSION_SET_STRING(&mysql->options, compression_algorithm,
8813 static_cast<const char *>(arg));
8814 8350 mysql->options.extension->total_configured_compression_algorithms = cnt;
8815 8350 } break;
8816 88793 case MYSQL_OPT_ZSTD_COMPRESSION_LEVEL:
8817
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 88793 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
88793 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
8818 88793 mysql->options.extension->zstd_compression_level =
8819 88793 *static_cast<const unsigned int *>(arg);
8820 88793 break;
8821
8822 11 case MYSQL_OPT_LOAD_DATA_LOCAL_DIR:
8823
2/4
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
11 if (set_load_data_local_infile_option(mysql,
8824 static_cast<const char *>(arg)))
8825 return 1;
8826 11 break;
8827 42 case MYSQL_OPT_SSL_SESSION_DATA:
8828
4/10
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 42 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 42 times.
✗ Branch 9 not taken.
42 EXTENSION_SET_STRING(&mysql->options, ssl_session_data,
8829 static_cast<const char *>(arg));
8830 42 break;
8831 default:
8832 return 1;
8833 }
8834 14992508 return 0;
8835 14992524 }
8836
8837 /**
8838 Return the current values for the options settable through mysql_options()
8839
8840 Returns the current values for all of the connection options.
8841 Callers should not manipulate the returned data !
8842 Data are valid at the time of returning them until the next C API CALL
8843 arg should always be a pointer to a variable of the appropriate type.
8844 type of variable, based on the parameter:
8845
8846 uint
8847 MYSQL_OPT_CONNECT_TIMEOUT, MYSQL_OPT_READ_TIMEOUT, MYSQL_OPT_WRITE_TIMEOUT,
8848 MYSQL_OPT_PROTOCOL, MYSQL_OPT_SSL_MODE, MYSQL_OPT_RETRY_COUNT
8849
8850 bool
8851 MYSQL_OPT_COMPRESS, MYSQL_OPT_LOCAL_INFILE,
8852 MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT,
8853 MYSQL_ENABLE_CLEARTEXT_PLUGIN, MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS,
8854 MYSQL_OPT_OPTIONAL_RESULTSET_METADATA
8855
8856 const char *
8857 MYSQL_READ_DEFAULT_FILE, MYSQL_READ_DEFAULT_GROUP,
8858 MYSQL_SET_CHARSET_DIR, MYSQL_SET_CHARSET_NAME,
8859 MYSQL_SHARED_MEMORY_BASE_NAME, MYSQL_SET_CLIENT_IP, MYSQL_OPT_BIND,
8860 MYSQL_PLUGIN_DIR, MYSQL_DEFAULT_AUTH, MYSQL_OPT_SSL_KEY, MYSQL_OPT_SSL_CERT,
8861 MYSQL_OPT_SSL_CA, MYSQL_OPT_SSL_CAPATH, MYSQL_OPT_SSL_CIPHER,
8862 MYSQL_OPT_TLS_CIPHERSUITES, MYSQL_OPT_SSL_CRL, MYSQL_OPT_SSL_CRLPATH,
8863 MYSQL_OPT_TLS_VERSION, MYSQL_SERVER_PUBLIC_KEY, MYSQL_OPT_SSL_FIPS_MODE
8864
8865 <none, error returned>
8866 MYSQL_OPT_NAMED_PIPE, MYSQL_OPT_CONNECT_ATTR_RESET,
8867 MYSQL_OPT_CONNECT_ATTR_DELETE, MYSQL_INIT_COMMAND
8868
8869 @param mysql The MYSQL connection to operate on
8870 @param option The option to return the value for
8871 @param [out] arg Must be non-null. Receives the current value.
8872 @return status
8873 @retval 0 SUCCESS
8874 */
8875
8876 856990 int STDCALL mysql_get_option(MYSQL *mysql, enum mysql_option option,
8877 const void *arg) {
8878
1/2
✓ Branch 0 taken 857223 times.
✗ Branch 1 not taken.
856990 DBUG_TRACE;
8879
3/8
✓ Branch 0 taken 857158 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 857080 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 857080 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
857223 DBUG_PRINT("enter", ("option: %d", (int)option));
8880
8881
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 857087 times.
857087 if (!arg) return 1;
8882
8883
36/38
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 7 times.
✓ Branch 6 taken 7 times.
✓ Branch 7 taken 7 times.
✓ Branch 8 taken 7 times.
✓ Branch 9 taken 26789 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✓ Branch 12 taken 7 times.
✓ Branch 13 taken 7 times.
✓ Branch 14 taken 26788 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 7 times.
✓ Branch 17 taken 7 times.
✓ Branch 18 taken 7 times.
✓ Branch 19 taken 7 times.
✓ Branch 20 taken 7 times.
✓ Branch 21 taken 7 times.
✓ Branch 22 taken 7 times.
✓ Branch 23 taken 7 times.
✓ Branch 24 taken 7 times.
✓ Branch 25 taken 6 times.
✓ Branch 26 taken 7 times.
✓ Branch 27 taken 7 times.
✓ Branch 28 taken 7 times.
✓ Branch 29 taken 6 times.
✓ Branch 30 taken 7 times.
✓ Branch 31 taken 7 times.
✓ Branch 32 taken 403556 times.
✓ Branch 33 taken 399449 times.
✓ Branch 34 taken 2 times.
✓ Branch 35 taken 11 times.
✓ Branch 36 taken 2 times.
✓ Branch 37 taken 284 times.
857087 switch (option) {
8884 13 case MYSQL_OPT_CONNECT_TIMEOUT:
8885 13 *(const_cast<uint *>(static_cast<const uint *>(arg))) =
8886 13 mysql->options.connect_timeout;
8887 13 break;
8888 13 case MYSQL_OPT_READ_TIMEOUT:
8889 13 *(const_cast<uint *>(static_cast<const uint *>(arg))) =
8890 13 mysql->options.read_timeout;
8891 13 break;
8892 13 case MYSQL_OPT_WRITE_TIMEOUT:
8893 13 *(const_cast<uint *>(static_cast<const uint *>(arg))) =
8894 13 mysql->options.write_timeout;
8895 13 break;
8896 7 case MYSQL_OPT_COMPRESS:
8897 7 *(const_cast<bool *>(static_cast<const bool *>(arg))) =
8898 7 mysql->options.compress;
8899 7 break;
8900 7 case MYSQL_OPT_LOCAL_INFILE: /* Allow LOAD DATA LOCAL ?*/
8901 7 *(const_cast<uint *>(static_cast<const uint *>(arg))) =
8902 7 (mysql->options.client_flag & CLIENT_LOCAL_FILES) != 0;
8903 7 break;
8904 7 case MYSQL_READ_DEFAULT_FILE:
8905 7 *(static_cast<char **>(const_cast<void *>(arg))) =
8906 7 mysql->options.my_cnf_file;
8907 7 break;
8908 7 case MYSQL_READ_DEFAULT_GROUP:
8909 7 *(static_cast<char **>(const_cast<void *>(arg))) =
8910 7 mysql->options.my_cnf_group;
8911 7 break;
8912 7 case MYSQL_SET_CHARSET_DIR:
8913 7 *(static_cast<char **>(const_cast<void *>(arg))) =
8914 7 mysql->options.charset_dir;
8915 7 break;
8916 7 case MYSQL_SET_CHARSET_NAME:
8917 7 *(static_cast<char **>(const_cast<void *>(arg))) =
8918 7 mysql->options.charset_name;
8919 7 break;
8920 26789 case MYSQL_OPT_PROTOCOL:
8921 26789 *(const_cast<uint *>(static_cast<const uint *>(arg))) =
8922 26789 mysql->options.protocol;
8923 26789 break;
8924 case MYSQL_SHARED_MEMORY_BASE_NAME:
8925 #if defined(_WIN32)
8926 *(static_cast<char **>(const_cast<void *>(arg))) =
8927 mysql->options.shared_memory_base_name;
8928 #else
8929 *(static_cast<char **>(const_cast<void *>(arg))) = const_cast<char *>("");
8930 #endif
8931 break;
8932 1 case MYSQL_REPORT_DATA_TRUNCATION:
8933 1 *(const_cast<bool *>(static_cast<const bool *>(arg))) =
8934 1 mysql->options.report_data_truncation;
8935 1 break;
8936 7 case MYSQL_OPT_RECONNECT:
8937 7 *(const_cast<bool *>(static_cast<const bool *>(arg))) = mysql->reconnect;
8938 7 break;
8939 7 case MYSQL_OPT_BIND:
8940 7 *(static_cast<char **>(const_cast<void *>(arg))) =
8941 7 mysql->options.bind_address;
8942 7 break;
8943 26788 case MYSQL_OPT_SSL_MODE:
8944 26788 *(const_cast<uint *>(static_cast<const uint *>(arg))) =
8945
1/2
✓ Branch 0 taken 26788 times.
✗ Branch 1 not taken.
26788 mysql->options.extension ? mysql->options.extension->ssl_mode : 0;
8946 26788 break;
8947 case MYSQL_OPT_SSL_FIPS_MODE:
8948 *(const_cast<uint *>(static_cast<const uint *>(arg))) =
8949 mysql->options.extension ? mysql->options.extension->ssl_fips_mode
8950 : 0;
8951 break;
8952 7 case MYSQL_PLUGIN_DIR:
8953 7 *(static_cast<char **>(const_cast<void *>(arg))) =
8954
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 mysql->options.extension ? mysql->options.extension->plugin_dir
8955 : nullptr;
8956 7 break;
8957 7 case MYSQL_DEFAULT_AUTH:
8958 7 *(static_cast<char **>(const_cast<void *>(arg))) =
8959
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 mysql->options.extension ? mysql->options.extension->default_auth
8960 : nullptr;
8961 7 break;
8962 7 case MYSQL_OPT_SSL_KEY:
8963 7 *(static_cast<char **>(const_cast<void *>(arg))) = mysql->options.ssl_key;
8964 7 break;
8965 7 case MYSQL_OPT_SSL_CERT:
8966 7 *(static_cast<char **>(const_cast<void *>(arg))) =
8967 7 mysql->options.ssl_cert;
8968 7 break;
8969 7 case MYSQL_OPT_SSL_CA:
8970 7 *(static_cast<char **>(const_cast<void *>(arg))) = mysql->options.ssl_ca;
8971 7 break;
8972 7 case MYSQL_OPT_SSL_CAPATH:
8973 7 *(static_cast<char **>(const_cast<void *>(arg))) =
8974 7 mysql->options.ssl_capath;
8975 7 break;
8976 7 case MYSQL_OPT_SSL_CIPHER:
8977 7 *(static_cast<char **>(const_cast<void *>(arg))) =
8978 7 mysql->options.ssl_cipher;
8979 7 break;
8980 7 case MYSQL_OPT_TLS_CIPHERSUITES:
8981 7 *(static_cast<char **>(const_cast<void *>(arg))) =
8982
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 mysql->options.extension ? mysql->options.extension->tls_ciphersuites
8983 : nullptr;
8984 7 break;
8985 7 case MYSQL_OPT_RETRY_COUNT:
8986 7 *(const_cast<uint *>(static_cast<const uint *>(arg))) =
8987
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 mysql->options.extension ? mysql->options.extension->retry_count : 1;
8988 7 break;
8989 6 case MYSQL_OPT_TLS_VERSION:
8990 6 *(static_cast<char **>(const_cast<void *>(arg))) =
8991
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 mysql->options.extension ? mysql->options.extension->tls_version
8992 : nullptr;
8993 6 break;
8994 7 case MYSQL_OPT_SSL_CRL:
8995 7 *(static_cast<char **>(const_cast<void *>(arg))) =
8996
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 mysql->options.extension ? mysql->options.extension->ssl_crl
8997 : nullptr;
8998 7 break;
8999 7 case MYSQL_OPT_SSL_CRLPATH:
9000 7 *(static_cast<char **>(const_cast<void *>(arg))) =
9001
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 mysql->options.extension ? mysql->options.extension->ssl_crlpath
9002 : nullptr;
9003 7 break;
9004 7 case MYSQL_SERVER_PUBLIC_KEY:
9005 7 *(static_cast<char **>(const_cast<void *>(arg))) =
9006 7 mysql->options.extension
9007
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 ? mysql->options.extension->server_public_key_path
9008 : nullptr;
9009 7 break;
9010 6 case MYSQL_OPT_GET_SERVER_PUBLIC_KEY:
9011 6 *(const_cast<bool *>(static_cast<const bool *>(arg))) =
9012
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
12 mysql->options.extension &&
9013
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 mysql->options.extension->get_server_public_key;
9014 6 break;
9015 7 case MYSQL_ENABLE_CLEARTEXT_PLUGIN:
9016 7 *(const_cast<bool *>(static_cast<const bool *>(arg))) =
9017
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
14 mysql->options.extension &&
9018
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
7 mysql->options.extension->enable_cleartext_plugin;
9019 7 break;
9020 7 case MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS:
9021 7 *(const_cast<bool *>(static_cast<const bool *>(arg))) =
9022 7 (mysql->options.client_flag & CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS) !=
9023 0;
9024 7 break;
9025
9026 403556 case MYSQL_OPT_MAX_ALLOWED_PACKET:
9027
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 403548 times.
403556 if (mysql)
9028 8 *(const_cast<ulong *>(static_cast<const ulong *>(arg))) =
9029 8 mysql->options.max_allowed_packet;
9030 else
9031 403548 *(const_cast<ulong *>(static_cast<const ulong *>(arg))) =
9032 g_max_allowed_packet;
9033 403556 break;
9034
9035 399449 case MYSQL_OPT_NET_BUFFER_LENGTH:
9036 399449 *(const_cast<ulong *>(static_cast<const ulong *>(arg))) =
9037 g_net_buffer_length;
9038 399449 break;
9039
9040 2 case MYSQL_OPT_OPTIONAL_RESULTSET_METADATA:
9041 2 *(const_cast<bool *>(static_cast<const bool *>(arg))) =
9042 2 (mysql->options.client_flag & CLIENT_OPTIONAL_RESULTSET_METADATA) !=
9043 0;
9044 2 break;
9045 11 case MYSQL_OPT_LOAD_DATA_LOCAL_DIR:
9046 11 *(static_cast<char **>(const_cast<void *>(arg))) =
9047
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 mysql->options.extension ? mysql->options.extension->load_data_dir
9048 : nullptr;
9049 11 break;
9050 2 case MYSQL_OPT_SSL_SESSION_DATA:
9051 2 *(static_cast<char **>(const_cast<void *>(arg))) =
9052 2 mysql->options.extension
9053
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 ? static_cast<char *>(mysql->options.extension->ssl_session_data)
9054 : nullptr;
9055 2 break;
9056
9057 284 case MYSQL_OPT_NAMED_PIPE: /* This option is deprecated */
9058 case MYSQL_INIT_COMMAND: /* Cumulative */
9059 case MYSQL_OPT_CONNECT_ATTR_RESET: /* Cumulative */
9060 case MYSQL_OPT_CONNECT_ATTR_DELETE: /* Cumulative */
9061 default:
9062 284 return 1;
9063 }
9064 856803 return 0;
9065 857087 }
9066
9067 10678220 int STDCALL mysql_options4(MYSQL *mysql, enum mysql_option option,
9068 const void *arg1, const void *arg2) {
9069
1/2
✓ Branch 0 taken 10679310 times.
✗ Branch 1 not taken.
10678220 DBUG_TRACE;
9070
3/8
✓ Branch 0 taken 10678964 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10678654 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10678654 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
10679310 DBUG_PRINT("enter", ("option: %d", (int)option));
9071
9072
2/3
✓ Branch 0 taken 10437944 times.
✓ Branch 1 taken 240692 times.
✗ Branch 2 not taken.
10678636 switch (option) {
9073 10437944 case MYSQL_OPT_CONNECT_ATTR_ADD: {
9074 10437944 const char *key = static_cast<const char *>(arg1);
9075 10437944 const char *value = static_cast<const char *>(arg2);
9076
1/2
✓ Branch 0 taken 10437978 times.
✗ Branch 1 not taken.
10437944 size_t key_len = arg1 ? strlen(key) : 0;
9077
1/2
✓ Branch 0 taken 10437986 times.
✗ Branch 1 not taken.
10437944 size_t value_len = arg2 ? strlen(value) : 0;
9078 10437944 size_t attr_storage_length = key_len + value_len;
9079
9080 /* we can't have a zero length key */
9081
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10437944 times.
10437944 if (!key_len) {
9082 set_mysql_error(mysql, CR_INVALID_PARAMETER_NO, unknown_sqlstate);
9083 1195 return 1;
9084 }
9085
9086 /* calculate the total storage length of the attribute */
9087
1/2
✓ Branch 0 taken 10437838 times.
✗ Branch 1 not taken.
10437944 attr_storage_length += get_length_store_length(key_len);
9088
1/2
✓ Branch 0 taken 10437778 times.
✗ Branch 1 not taken.
10437838 attr_storage_length += get_length_store_length(value_len);
9089
9090
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10437778 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
10437778 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
9091
9092 /*
9093 Throw and error if the maximum combined length of the attribute value
9094 will be greater than the maximum that we can safely transmit.
9095 */
9096 10437778 if (attr_storage_length +
9097
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10437778 times.
10437778 mysql->options.extension->connection_attributes_length >
9098 MAX_CONNECTION_ATTR_STORAGE_LENGTH) {
9099 set_mysql_error(mysql, CR_INVALID_PARAMETER_NO, unknown_sqlstate);
9100 return 1;
9101 }
9102
9103
2/2
✓ Branch 0 taken 374180 times.
✓ Branch 1 taken 10063598 times.
10437778 if (!mysql->options.extension->connection_attributes) {
9104 374231 mysql->options.extension->connection_attributes =
9105
1/2
✓ Branch 0 taken 374158 times.
✗ Branch 1 not taken.
748411 new (std::nothrow) My_hash();
9106
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 374231 times.
374231 if (!mysql->options.extension->connection_attributes) {
9107 set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
9108 return 1;
9109 }
9110 }
9111 20876035 if (!mysql->options.extension->connection_attributes->hash
9112
1/2
✓ Branch 0 taken 10438206 times.
✗ Branch 1 not taken.
10437829 .emplace(key, value)
9113
2/2
✓ Branch 0 taken 1195 times.
✓ Branch 1 taken 10437011 times.
10438206 .second) {
9114 /* can't insert the value */
9115
1/2
✓ Branch 0 taken 1195 times.
✗ Branch 1 not taken.
1195 set_mysql_error(mysql, CR_DUPLICATE_CONNECTION_ATTR, unknown_sqlstate);
9116 1195 return 1;
9117 }
9118
9119 10437011 mysql->options.extension->connection_attributes_length +=
9120 attr_storage_length;
9121
9122 10437011 break;
9123 }
9124 240692 case MYSQL_OPT_USER_PASSWORD: {
9125 240692 unsigned int factor = *static_cast<const uint *>(arg1) - 1;
9126
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 240692 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
240692 ENSURE_EXTENSIONS_PRESENT(&mysql->options);
9127 switch (factor) {
9128 240656 case 0:
9129
1/2
✓ Branch 0 taken 240702 times.
✗ Branch 1 not taken.
240656 my_free(mysql->options.extension->client_auth_info[0].password);
9130 481454 mysql->options.extension->client_auth_info[0].password =
9131
1/2
✓ Branch 0 taken 240752 times.
✗ Branch 1 not taken.
240702 my_strdup(key_memory_mysql_options,
9132 static_cast<const char *>(arg2), MYF(MY_FAE));
9133 240752 break;
9134 case 1:
9135 my_free(mysql->options.extension->client_auth_info[1].password);
9136 mysql->options.extension->client_auth_info[1].password =
9137 my_strdup(key_memory_mysql_options,
9138 static_cast<const char *>(arg2), MYF(MY_FAE));
9139 break;
9140 case 2:
9141 my_free(mysql->options.extension->client_auth_info[2].password);
9142 mysql->options.extension->client_auth_info[2].password =
9143 my_strdup(key_memory_mysql_options,
9144 static_cast<const char *>(arg2), MYF(MY_FAE));
9145 break;
9146 36 default:
9147
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
36 set_mysql_error(mysql, CR_INVALID_FACTOR_NO, unknown_sqlstate);
9148 return 1;
9149 }
9150 240752 break;
9151 }
9152 default:
9153 return 1;
9154 }
9155 10677763 return 0;
9156 10678958 }
9157
9158 /****************************************************************************
9159 Functions to get information from the MySQL structure
9160 These are functions to make shared libraries more usable.
9161 ****************************************************************************/
9162
9163 /* MYSQL_RES */
9164 41213 my_ulonglong STDCALL mysql_num_rows(MYSQL_RES *res) { return res->row_count; }
9165
9166 21310729 unsigned int STDCALL mysql_num_fields(MYSQL_RES *res) {
9167 21310729 return res->field_count;
9168 }
9169
9170 12787117 uint STDCALL mysql_errno(MYSQL *mysql) {
9171
1/2
✓ Branch 0 taken 12787117 times.
✗ Branch 1 not taken.
12787117 return mysql ? mysql->net.last_errno : mysql_server_last_errno;
9172 }
9173
9174 2071802 const char *STDCALL mysql_error(MYSQL *mysql) {
9175
1/2
✓ Branch 0 taken 2071802 times.
✗ Branch 1 not taken.
2071802 return mysql ? mysql->net.last_error : mysql_server_last_error;
9176 }
9177
9178 /**
9179 Read data and its length from a LIST node.
9180
9181 Assumes LIST which stores data blobs in LEX_STRING structures,
9182 where LEX_STRING::str is pointer to the data and LEX_STRING::length
9183 is the length of this data.
9184
9185 If node is NULL then data and length are set to NULL and 0, respectively,
9186 and function returns 0, otherwise, if data has been read from the node,
9187 function returns 1.
9188 */
9189
9190 4006 static int get_data_and_length(LIST *node, const char **data, size_t *length) {
9191
3/4
✓ Branch 0 taken 478 times.
✓ Branch 1 taken 3528 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 478 times.
4006 assert(!node || node->data);
9192
3/4
✓ Branch 0 taken 4006 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 478 times.
✓ Branch 3 taken 3528 times.
4006 if (data) *data = node ? ((LEX_STRING *)(node->data))->str : nullptr;
9193
3/4
✓ Branch 0 taken 4006 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 478 times.
✓ Branch 3 taken 3528 times.
4006 if (length) *length = node ? ((LEX_STRING *)(node->data))->length : 0;
9194
9195 4006 return node ? 0 : 1;
9196 }
9197
9198 /**
9199 Get the first state change information received from the server.
9200
9201 @param [in] mysql mysql handle
9202 @param [in] type state change type
9203 @param [out] data buffer to store the data
9204 @param [out] length length of the data
9205
9206 @return
9207 0 - Valid data stored
9208 1 - No data
9209 */
9210
9211 3528 int STDCALL mysql_session_track_get_first(MYSQL *mysql,
9212 enum enum_session_state_type type,
9213 const char **data, size_t *length) {
9214
2/4
✓ Branch 0 taken 3528 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3528 times.
✗ Branch 3 not taken.
3528 STATE_INFO *info = STATE_DATA(mysql);
9215
9216
3/6
✓ Branch 0 taken 3528 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3528 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3528 times.
✗ Branch 5 not taken.
3528 if (!info || !IS_SESSION_STATE_TYPE(type) ||
9217
2/2
✓ Branch 0 taken 3141 times.
✓ Branch 1 taken 387 times.
3528 !(info->info_list[type].head_node))
9218 3141 return get_data_and_length(nullptr, data, length);
9219
9220 387 info->info_list[type].current_node = info->info_list[type].head_node;
9221
9222 387 return mysql_session_track_get_next(mysql, type, data, length);
9223 }
9224
9225 /**
9226 Get the subsequent state change information received from the server.
9227
9228 @param [in] mysql mysql handle
9229 @param [in] type state change type
9230 @param [out] data buffer to store the data
9231 @param [out] length length of the data
9232
9233 @return
9234 0 - Valid data stored
9235 1 - No data
9236 */
9237
9238 865 int STDCALL mysql_session_track_get_next(MYSQL *mysql,
9239 enum enum_session_state_type type,
9240 const char **data, size_t *length) {
9241
2/4
✓ Branch 0 taken 865 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 865 times.
✗ Branch 3 not taken.
865 STATE_INFO *info = STATE_DATA(mysql);
9242 int ret;
9243
9244
3/6
✓ Branch 0 taken 865 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 865 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 865 times.
✗ Branch 5 not taken.
865 if (!info || !IS_SESSION_STATE_TYPE(type) ||
9245
2/2
✓ Branch 0 taken 387 times.
✓ Branch 1 taken 478 times.
865 !(info->info_list[type].current_node))
9246 387 return get_data_and_length(nullptr, data, length);
9247
9248 478 ret = get_data_and_length(info->info_list[type].current_node, data, length);
9249
9250 478 info->info_list[type].current_node =
9251 478 list_rest(info->info_list[type].current_node);
9252
9253 478 return ret;
9254 }
9255
9256 /*
9257 Get version number for server in a form easy to test on
9258
9259 SYNOPSIS
9260 mysql_get_server_version()
9261 mysql Connection
9262
9263 EXAMPLE
9264 4.1.0-alfa -> 40100
9265
9266 NOTES
9267 We will ensure that a newer server always has a bigger number.
9268
9269 RETURN
9270 Signed number > 323000
9271 Zero if there is no connection
9272 */
9273
9274 1248781 ulong STDCALL mysql_get_server_version(MYSQL *mysql) {
9275 1248781 ulong major = 0, minor = 0, version = 0;
9276
9277
1/2
✓ Branch 0 taken 1248781 times.
✗ Branch 1 not taken.
1248781 if (mysql->server_version) {
9278 1248781 char *pos = mysql->server_version, *end_pos;
9279 1248781 major = strtoul(pos, &end_pos, 10);
9280 1248781 pos = end_pos + 1;
9281 1248781 minor = strtoul(pos, &end_pos, 10);
9282 1248781 pos = end_pos + 1;
9283 1248781 version = strtoul(pos, &end_pos, 10);
9284 } else {
9285 set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
9286 }
9287
9288 1248781 return major * 10000 + minor * 100 + version;
9289 }
9290
9291 /*
9292 mysql_set_character_set function sends SET NAMES cs_name to
9293 the server (which changes character_set_client, character_set_result
9294 and character_set_connection) and updates mysql->charset so other
9295 functions like mysql_real_escape will work correctly.
9296 */
9297 39923 int STDCALL mysql_set_character_set(MYSQL *mysql, const char *cs_name) {
9298 CHARSET_INFO *cs;
9299 39923 const char *save_csdir = charsets_dir;
9300
9301
2/2
✓ Branch 0 taken 11726 times.
✓ Branch 1 taken 28197 times.
39923 if (mysql->options.charset_dir) {
9302 #ifdef MYSQL_SERVER
9303 // Do not change charsets_dir, it is not thread safe.
9304 assert(false);
9305 #else
9306 11726 charsets_dir = mysql->options.charset_dir;
9307 #endif
9308 }
9309
2/2
✓ Branch 0 taken 27066 times.
✓ Branch 1 taken 12857 times.
39923 if (!mysql->net.vio) {
9310 /* Initialize with automatic OS character set detection. */
9311 27066 mysql_options(mysql, MYSQL_SET_CHARSET_NAME, cs_name);
9312 27066 mysql_init_character_set(mysql);
9313 /*
9314 In case of automatic OS character set detection
9315 mysql_init_character_set changes mysql->options.charset_name
9316 from "auto" to the real character set name.
9317 Reset cs_name to the detected character set name, accordingly.
9318 */
9319 27066 cs_name = mysql->options.charset_name;
9320 }
9321
9322
2/4
✓ Branch 0 taken 39923 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39923 times.
✗ Branch 3 not taken.
79846 if (strlen(cs_name) < MY_CS_NAME_SIZE &&
9323
1/2
✓ Branch 0 taken 39923 times.
✗ Branch 1 not taken.
39923 (cs = get_charset_by_csname(cs_name, MY_CS_PRIMARY, MYF(0)))) {
9324 char buff[MY_CS_NAME_SIZE + 10];
9325 39923 charsets_dir = save_csdir;
9326
2/2
✓ Branch 0 taken 27066 times.
✓ Branch 1 taken 12857 times.
39923 if (!mysql->net.vio) {
9327 /* If there is no connection yet we don't send "SET NAMES" query */
9328 27066 mysql->charset = cs;
9329 27066 return 0;
9330 }
9331 /* Skip execution of "SET NAMES" for pre-4.1 servers */
9332
2/4
✓ Branch 0 taken 12857 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 12857 times.
12857 if (mysql_get_server_version(mysql) < 40100) return 0;
9333 12857 sprintf(buff, "SET NAMES %s", cs_name);
9334
2/4
✓ Branch 0 taken 12857 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12857 times.
✗ Branch 3 not taken.
12857 if (!mysql_real_query(mysql, buff, (ulong)strlen(buff))) {
9335 12857 mysql->charset = cs;
9336 }
9337 } else {
9338 char cs_dir_name[FN_REFLEN];
9339 get_charsets_dir(cs_dir_name);
9340 set_mysql_extended_error(mysql, CR_CANT_READ_CHARSET, unknown_sqlstate,
9341 ER_CLIENT(CR_CANT_READ_CHARSET), cs_name,
9342 cs_dir_name);
9343 }
9344 12857 charsets_dir = save_csdir;
9345 12857 return mysql->net.last_errno;
9346 }
9347
9348 /**
9349 Client authentication plugin that does native MySQL authentication
9350 using a 20-byte (4.1+) scramble
9351
9352 @param vio the channel to operate on
9353 @param mysql the MYSQL structure to operate on
9354
9355 @retval -1 ::CR_OK : Success
9356 @retval 1 ::CR_ERROR : error reading
9357 @retval 2012 ::CR_SERVER_HANDSHAKE_ERR : malformed handshake data
9358 */
9359 19052 static int native_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) {
9360 int pkt_len;
9361 uchar *pkt;
9362
9363
1/2
✓ Branch 0 taken 19052 times.
✗ Branch 1 not taken.
19052 DBUG_TRACE;
9364
9365 /* read the scramble */
9366
3/4
✓ Branch 0 taken 19052 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 19019 times.
19052 if ((pkt_len = vio->read_packet(vio, &pkt)) < 0) return CR_ERROR;
9367
9368
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19019 times.
19019 if (pkt_len != SCRAMBLE_LENGTH + 1) return CR_SERVER_HANDSHAKE_ERR;
9369
9370 /* save it in MYSQL */
9371 19019 memcpy(mysql->scramble, pkt, SCRAMBLE_LENGTH);
9372 19019 mysql->scramble[SCRAMBLE_LENGTH] = 0;
9373
9374
2/2
✓ Branch 0 taken 17086 times.
✓ Branch 1 taken 1933 times.
19019 if (mysql->passwd[0]) {
9375 char scrambled[SCRAMBLE_LENGTH + 1];
9376
3/8
✓ Branch 0 taken 17086 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17086 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 17086 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
17086 DBUG_PRINT("info", ("sending scramble"));
9377
1/2
✓ Branch 0 taken 17086 times.
✗ Branch 1 not taken.
17086 scramble(scrambled, (char *)pkt, mysql->passwd);
9378
2/4
✓ Branch 0 taken 17086 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 17086 times.
17086 if (vio->write_packet(vio, (uchar *)scrambled, SCRAMBLE_LENGTH))
9379 return CR_ERROR;
9380 } else {
9381
3/8
✓ Branch 0 taken 1933 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1933 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1933 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1933 DBUG_PRINT("info", ("no password"));
9382
2/4
✓ Branch 0 taken 1933 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1933 times.
1933 if (vio->write_packet(vio, nullptr, 0)) /* no password */
9383 return CR_ERROR;
9384 }
9385
9386 19019 return CR_OK;
9387 19052 }
9388
9389 /**
9390 Client authentication plugin that does native MySQL authentication
9391 in a nonblocking way.
9392
9393 @param[in] vio the channel to operate on
9394 @param[in] mysql the MYSQL structure to operate on
9395 @param[out] result CR_OK : Success, CR_ERROR : error reading,
9396 CR_SERVER_HANDSHAKE_ERR : malformed handshake data
9397
9398 @retval NET_ASYNC_NOT_READY authentication not yet complete
9399 @retval NET_ASYNC_COMPLETE authentication done
9400 */
9401 6 static net_async_status native_password_auth_client_nonblocking(
9402 MYSQL_PLUGIN_VIO *vio, MYSQL *mysql, int *result) {
9403
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 DBUG_TRACE;
9404 int io_result;
9405 uchar *pkt;
9406
2/6
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
6 mysql_async_auth *ctx = ASYNC_DATA(mysql)->connect_context->auth_context;
9407
9408 6 switch (static_cast<client_auth_native_password_plugin_status>(
9409
1/3
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
6 ctx->client_auth_plugin_state)) {
9410 6 case client_auth_native_password_plugin_status::NATIVE_READING_PASSWORD:
9411
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (((MCPVIO_EXT *)vio)->mysql_change_user) {
9412 /* mysql_change_user_nonblocking not implemented yet. */
9413 assert(false);
9414 } else {
9415 /* read the scramble */
9416 net_async_status status =
9417
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 vio->read_packet_nonblocking(vio, &pkt, &io_result);
9418
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (status == NET_ASYNC_NOT_READY) {
9419 return NET_ASYNC_NOT_READY;
9420 }
9421
9422
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (io_result < 0) {
9423 *result = CR_ERROR;
9424 return NET_ASYNC_COMPLETE;
9425 }
9426
9427
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (io_result != SCRAMBLE_LENGTH + 1) {
9428 *result = CR_SERVER_HANDSHAKE_ERR;
9429 return NET_ASYNC_COMPLETE;
9430 }
9431
9432 /* save it in MYSQL */
9433 6 memcpy(mysql->scramble, pkt, SCRAMBLE_LENGTH);
9434 6 mysql->scramble[SCRAMBLE_LENGTH] = 0;
9435 }
9436 6 ctx->client_auth_plugin_state = (int)
9437 client_auth_native_password_plugin_status::NATIVE_WRITING_RESPONSE;
9438
9439 [[fallthrough]];
9440
9441 6 case client_auth_native_password_plugin_status::NATIVE_WRITING_RESPONSE:
9442
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (mysql->passwd[0]) {
9443 char scrambled[SCRAMBLE_LENGTH + 1];
9444
3/8
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
3 DBUG_PRINT("info", ("sending scramble"));
9445
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 scramble(scrambled, (char *)pkt, mysql->passwd);
9446
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 net_async_status status = vio->write_packet_nonblocking(
9447 vio, (uchar *)scrambled, SCRAMBLE_LENGTH, &io_result);
9448
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (status == NET_ASYNC_NOT_READY) {
9449 return NET_ASYNC_NOT_READY;
9450 }
9451
9452
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (io_result < 0) {
9453 *result = CR_ERROR;
9454 return NET_ASYNC_COMPLETE;
9455 }
9456 } else {
9457
3/8
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
3 DBUG_PRINT("info", ("no password"));
9458
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 net_async_status status = vio->write_packet_nonblocking(
9459 vio, nullptr, 0, &io_result); /* no password */
9460
9461
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (status == NET_ASYNC_NOT_READY) {
9462 return NET_ASYNC_NOT_READY;
9463 }
9464
9465
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (io_result < 0) {
9466 *result = CR_ERROR;
9467 return NET_ASYNC_COMPLETE;
9468 }
9469 }
9470 6 break;
9471 default:
9472 assert(0);
9473 }
9474
9475 6 *result = CR_OK;
9476 6 return NET_ASYNC_COMPLETE;
9477 6 }
9478 /* clang-format off */
9479 /**
9480 @page page_protocol_connection_phase_authentication_methods_clear_text_password Clear text client plugin
9481
9482 <ul>
9483 <li>
9484 This client side plugin is used by a number of server plugins:
9485 LDAP (*authentication_ldap_simple*) and PAM (*authentication_pam*) to name a few.
9486 </li>
9487 <li>
9488 The client name is *mysql_clear_password*
9489 </li>
9490 <li>
9491 Client side requires nothing from the server. But the server generates
9492 and sends a 20-byte
9493 @ref page_protocol_connection_phase_authentication_methods_native_password_authentication
9494 compatible scramble.
9495 </li>
9496 <li>
9497 Client side sends the password in clear text to the server
9498 </li>
9499 </ul>
9500
9501 @startuml
9502 Server->Client: 20 bytes of scramble to be ignored
9503 Client->Server: The clear text password. null terminated.
9504 @enduml
9505
9506 @note
9507 Sending the scramble is not necessary for the clear text
9508 method, but, since the server always initiates the exchange by
9509 sending @ref page_protocol_connection_phase_packets_protocol_handshake
9510 and that one has a placeholder for authentication plugin dependent data the
9511 server does fill that space with a scramble should it come to pass that
9512 it will back down to
9513 @ref page_protocol_connection_phase_authentication_methods_native_password_authentication.
9514 This is also why it's OK no to specifically read this in
9515 @ref clear_password_auth_client since it's already read as a part of
9516 the initial exchange.
9517
9518
9519 @sa ::clear_password_auth_client, ::server_mpvio_write_packet,
9520 ::send_server_handshake_packet
9521 */
9522 /* clang-format on */
9523
9524 /**
9525 The main function of the mysql_clear_password authentication plugin.
9526 */
9527
9528 12 static int clear_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) {
9529 int res;
9530
9531 /* send password in clear text */
9532 24 res = vio->write_packet(vio, (const unsigned char *)mysql->passwd,
9533 12 (int)strlen(mysql->passwd) + 1);
9534
9535
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 return res ? CR_ERROR : CR_OK;
9536 }
9537
9538 293009 const char *fieldtype2str(enum enum_field_types type) {
9539
16/31
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 271 times.
✓ Branch 4 taken 800 times.
✓ Branch 5 taken 2671 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 265080 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 131 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 312 times.
✓ Branch 13 taken 7 times.
✓ Branch 14 taken 14662 times.
✓ Branch 15 taken 3681 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✓ Branch 21 taken 6 times.
✓ Branch 22 taken 260 times.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✓ Branch 26 taken 4954 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 168 times.
✓ Branch 29 taken 1 times.
✓ Branch 30 taken 4 times.
293009 switch (type) {
9540 1 case MYSQL_TYPE_BIT:
9541 1 return "BIT";
9542 case MYSQL_TYPE_BLOB:
9543 return "BLOB";
9544 case MYSQL_TYPE_BOOL:
9545 return "BOOLEAN";
9546 271 case MYSQL_TYPE_DATE:
9547 271 return "DATE";
9548 800 case MYSQL_TYPE_DATETIME:
9549 800 return "DATETIME";
9550 2671 case MYSQL_TYPE_NEWDECIMAL:
9551 2671 return "NEWDECIMAL";
9552 case MYSQL_TYPE_DECIMAL:
9553 return "DECIMAL";
9554 265080 case MYSQL_TYPE_DOUBLE:
9555 265080 return "DOUBLE";
9556 case MYSQL_TYPE_ENUM:
9557 return "ENUM";
9558 case MYSQL_TYPE_FLOAT:
9559 return "FLOAT";
9560 131 case MYSQL_TYPE_GEOMETRY:
9561 131 return "GEOMETRY";
9562 case MYSQL_TYPE_INT24:
9563 return "INT24";
9564 312 case MYSQL_TYPE_JSON:
9565 312 return "JSON";
9566 7 case MYSQL_TYPE_LONG:
9567 7 return "LONG";
9568 14662 case MYSQL_TYPE_LONGLONG:
9569 14662 return "LONGLONG";
9570 3681 case MYSQL_TYPE_LONG_BLOB:
9571 3681 return "LONG_BLOB";
9572 case MYSQL_TYPE_MEDIUM_BLOB:
9573 return "MEDIUM_BLOB";
9574 case MYSQL_TYPE_NEWDATE:
9575 return "NEWDATE";
9576 case MYSQL_TYPE_NULL:
9577 return "NULL";
9578 case MYSQL_TYPE_SET:
9579 return "SET";
9580 case MYSQL_TYPE_SHORT:
9581 return "SHORT";
9582 6 case MYSQL_TYPE_STRING:
9583 6 return "STRING";
9584 260 case MYSQL_TYPE_TIME:
9585 260 return "TIME";
9586 case MYSQL_TYPE_TIMESTAMP:
9587 return "TIMESTAMP";
9588 case MYSQL_TYPE_TINY:
9589 return "TINY";
9590 case MYSQL_TYPE_TINY_BLOB:
9591 return "TINY_BLOB";
9592 4954 case MYSQL_TYPE_VARCHAR:
9593 4954 return "VARCHAR";
9594 case MYSQL_TYPE_VAR_STRING:
9595 return "VAR_STRING";
9596 168 case MYSQL_TYPE_YEAR:
9597 168 return "YEAR";
9598 1 case MYSQL_TYPE_INVALID:
9599 1 return "?-invalid-?";
9600 4 default:
9601 4 return "?-unknown-?";
9602 }
9603 }
9604